{ config
, lib
, pkgs
, inputs
, ...
} @ args:

with lib;
let
  cfg = config.my.programs.hyprland;

  hyprland = pkgs.hyprland.override { nvidiaPatches = cfg.nvidiaSupport; };
in
{
  options.my.programs.hyprland = {
    enable = mkEnableOption "hyprland";
    nvidiaSupport = mkEnableOption "enable nvidia Support";
    blur = mkOption {
      type = types.bool;
      description = "enable window blurring";
      default = true;
    };
    shadows = mkOption {
      type = types.bool;
      description = "enable window shadows";
      default = true;
    };
  };

  config = mkIf cfg.enable {
    my = {
      programs = {
        wallpaper.enable = true;
        kitty.enable = true;
        rofi.enable = true;

      };
      wallpapers.enable = true;
      services.dunst.enable = true;
    };

    # enable home-manager module
    home-manager.users.moritz = {
      # import home-manager module
      imports = [ inputs.hyprland.homeManagerModules.default ];

      wayland.windowManager.hyprland = {
        enable = true;
        package = hyprland;
        recommendedEnvironment = true;
        extraConfig = import ./_config.nix args;
      };
    };


    # add waybar as a status bar
    home-manager.users.moritz.programs.waybar = {
      enable = true;

      # use package with hyprland support for switching workspaces
      package = pkgs.symlinkJoin {
        name = "waybar-hyprland";
        paths = [ pkgs.waybar-hyprland ];
        nativeBuildInputs = [ pkgs.makeWrapper ];
        postBuild = ''
          wrapProgram $out/bin/waybar \
            --prefix PATH ":" "${hyprland}/bin"
        '';
      };


      # start using systemd service
      systemd = {
        enable = true;
        target = "graphical-session.target";
      };

      settings = {
        mainBar = {
          layer = "top";
          position = "top";
          height = 20;
          modules-left = [ "wlr/workspaces" ];
          modules-center = [ "hyprland/window" ];
          modules-right = [ "network" "memory" "cpu" "battery" "clock" ];
          modules = {
            "wlr/workspaces" = {
              on-click = "activate";
            };
          };
        };
      };
    };

    # lock screen after timeout
    home-manager.users.moritz = {
      services.swayidle = {
        enable = true;
        events = [
          {
            event = "before-sleep";
            command = "${getExe pkgs.swaylock} -fF";
          }
          {
            event = "lock";
            command = "${getExe pkgs.swaylock} -fF";
          }
        ];
        timeouts =
          let
            lockTimeout = 10;
          in
          [
            {
              timeout = lockTimeout * 60 - 10;
              command = "${pkgs.libnotify}/bin/notify-send 'Locking screen!'";
            }
            {
              timeout = lockTimeout * 60;
              command = "${hyprland}/bin/hyprctl dispatch dpms off";
              resumeCommand = "${hyprland}/bin/hyprctl dispatch dpms on";
            }
            {
              timeout = lockTimeout * 60 + 10;
              command = "${pkgs.systemd}/bin/loginctl lock-session";
            }
          ] ++ optional
            (!cfg.nvidiaSupport) # TODO https://github.com/hyprwm/Hyprland/issues/1728
            {
              timeout = 30 * 60;
              command = "${pkgs.systemd}/bin/systemctl suspend-and-hibernate";
            };
        systemdTarget = "hyprland-session.target";
      };
    };

    # adds pam module for swaylock
    security.pam.services.swaylock = { };

    # only consider graphical-session.target started when hyprland-sesstion.target is reached
    systemd.user.targets.hyprland-session = {
      partOf = [ "graphical-session.target" ];
      wantedBy = [ "graphical-session.target" ];
      before = [ "graphical-session.target" ];
    };

    systemd.user.services.xdg-desktop-portal-hyprland = {
      after = [ "hyrpland-session.target" ];
      requiredBy = [ "xdg-desktop-portal.service" ];
    };

    home-manager.users.moritz.systemd.user.services.nextcloud-client.Service = {
      RestartSec = "500ms";
      Restart = "on-failure";
    };

    # add user packages for wayland and hyprland in particular
    users.users.moritz.packages = with pkgs; [
      brightnessctl # control brightness
      grimblast # screenshot tool for hyprland
      pamixer # pulse audio cli
      playerctl # control media playback
      slurp # region select for wayland (for screensharing)
      wdisplays # manage monitors
      wl-clipboard # clipboard tool for wayland
    ];


    # additional environment variables
    environment.sessionVariables =
      {
        XDG_CURRENT_DESKTOP = "Hyprland";
        XDG_SESSION_TYPE = "wayland";
        XDG_SESSION_DESKTOP = "Hyprland";
        QT_AUTO_SCREEN_SCALE_FACTOR = "1";
        QT_QPA_PLATFORM = "wayland;xcb";
        QT_WAYLAND_DISABLE_WINDOWDECORATION = "1";
        QT_QPA_PLATFORMTHEME = "qt5ct";
        _JAVA_AWT_WM_NONEREPARENTING = "1";
      } // (optionalAttrs cfg.nvidiaSupport
        {
          LIBVA_DRIVER_NAME = "nvidia";
          GBM_BACKEND = "nvidia-drm";
          __GLX_VENDOR_LIBRARY_NAME = "nvidia";
          WLR_NO_HARDWARE_CURSORS = "1";
          __GL_VRR_ALLOWED = "0";
        });


    services = {
      dbus.enable = true;
      # use pipewire (needed for screensharing)
      pipewire = {
        enable = true;
        alsa.enable = true;
        alsa.support32Bit = true;
        pulse.enable = true;
      };
      xserver = {
        enable = true;
        displayManager = {
          lightdm.enable = true;
          autoLogin = {
            enable = true;
            user = "moritz";
          };
          defaultSession = "hyprland";
          sessionPackages = [ hyprland ]; # can't set the defaultSession otherwise
        };
      };
    };
    security.rtkit.enable = true;


    # desktop portal (for screensharing)
    xdg.portal = {
      enable = true;
      wlr.enable = mkForce false;
      extraPortals = [ pkgs.xdg-desktop-portal-hyprland ];
    };
  };
}
