{ inputs, lib, config, system, pkgs, ... }:

with lib;
let
  cfg = config.modules.desktop.hyprland;
  hyprpkgs = inputs.hyprland.packages.${system};
in {
  options.modules.desktop.hyprland = {
    enable = mkEnableOption "Enable hyprland, a dynamic tiling wayland compositor based on wlroots that doesn't sacrifice on its looks";
    package = mkOption {
      type = types.package;
      default = hyprpkgs.hyprland;
      example = "pkgs.hyprland";
    };
    portalPackage = mkOption {
      type = types.package;
      default = hyprpkgs.xdg-desktop-portal-hyprland;
      example = "pkgs.xdg-desktop-portal-hyprland";
    };
  };

  config = mkIf cfg.enable {
    services.displayManager.sessionPackages = [ cfg.package ];

    xdg.portal = {
      enable = true;
      extraPortals = [ pkgs.xdg-desktop-portal-gtk cfg.portalPackage ];
      config = {
        common = {
          default = [ "hyprland" "gtk" ];
        };
      };
    };

    # fixes a few things, most notibly, xwayland
    programs.hyprland = {
      enable = true;
      xwayland.enable = true;
      package = cfg.package;
      portalPackage = cfg.portalPackage;
    };

    hm.wayland.windowManager.hyprland = {
      enable = true;
      xwayland.enable = true;
      package = cfg.package;

      systemd.variables = [ "--all" ];

      settings = let
        wobSock = config.modules.desktop.wob.sockPath;
      in {
        source = [];

        "$mod" = "SUPER";
        bindm = [ # "bind mouse"
          # move/resize windows with mod + lmb/rmb and dragging
          "$mod, mouse:272, movewindow"
          "$mod, mouse:273, resizewindow"
        ];
        bindel = (if config.modules.desktop.wob.enable then [ # "bind held & locked"
          ", XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+ && wpctl get-volume @DEFAULT_AUDIO_SINK@ | sed 's/[^0-9]//g' > ${wobSock}"
          ", XF86AudioLowerVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%- && wpctl get-volume @DEFAULT_AUDIO_SINK@ | sed 's/[^0-9]//g' > ${wobSock}"
          ", XF86MonBrightnessUp, exec, ${lib.getExe pkgs.brightnessctl} -c backlight s +5% | sed -n 's/.*(\\([0-9]*\\)%).*/\\1/p' > ${wobSock}"
          ", XF86MonBrightnessDown, exec, ${lib.getExe pkgs.brightnessctl} -c backlight s 5%- | sed -n 's/.*(\\([0-9]*\\)%).*/\\1/p' > ${wobSock}"
        ] else [
          ", XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+"
          ", XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"
          ", XF86MonBrightnessUp, exec, ${lib.getExe pkgs.brightnessctl} -c backlight s +5%"
          ", XF86MonBrightnessDown, exec, ${lib.getExe pkgs.brightnessctl} -c backlight s 5%-"
        ]);
        bindl = ([ # "bind locked"
          ",switch:Lid Switch,exec,${lib.getExe config.modules.desktop.hyprlock.package}"

          ", XF86AudioPlay, exec, ${lib.getExe pkgs.playerctl} play-pause"
          ", XF86AudioStop, exec, ${lib.getExe pkgs.playerctl} stop"
          ", XF86AudioPrev, exec, ${lib.getExe pkgs.playerctl} previous"
          ", XF86AudioNext, exec, ${lib.getExe pkgs.playerctl} next"

          ", XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"
        ] ++ (if config.modules.desktop.wob.enable then [
          ", XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle && (wpctl get-volume @DEFAULT_AUDIO_SINK@ | grep -q MUTED && echo 0 > ${wobSock}) || wpctl get-volume @DEFAULT_AUDIO_SINK@ | sed 's/[^0-9]//g' > ${wobSock}"
        ] else [
          ", XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"
        ]));
        bindr = [ # "bind released"
          "SUPER, Super_L, exec, ${lib.getExe pkgs.nwg-drawer}"
        ];
        bind = let 
          screenshotScript = pkgs.writeScript "screenshot" ''
            temp_file=$(mktemp)
            trap 'rm -f "$temp_file"' EXIT

            ${lib.getExe pkgs.grimblast} --freeze save area - > "$temp_file" || exit 1

            cat "$temp_file" | ${lib.getExe pkgs.wl-clipboard-x11} -selection clipboard -t image/png

            action=$(${pkgs.libnotify}/bin/notify-send "Screenshot Captured" \
              --app-name="Screenshot" \
              --urgency=normal \
              --action="default=Edit Image" \
              --icon "$temp_file" \
              "Click to annotate image")

            case "$action" in
              default)
                ${lib.getExe pkgs.satty} --filename "$temp_file"
                ;;
            esac
          '';
        in [
          "$mod, R, exec, ${lib.getExe pkgs.rofi-wayland} -show run"
          ", print, exec, ${screenshotScript}"
          "$mod, T, exec, ${lib.getExe pkgs.wezterm}"

          "$mod, Q, killactive, "
          "$mod, F, togglefloating, "
          "$mod, P, pseudo, " # dwindle
          "$mod, J, togglesplit, " # dwindle

          # move focus with mod + arrow keys
          "$mod, left, movefocus, l"
          "$mod, right, movefocus, r"
          "$mod, up, movefocus, u"
          "$mod, down, movefocus, d"

          # example special workspace (scratchpad)
          "$mod, S, togglespecialworkspace, magic"
          "$mod SHIFT, S, movetoworkspace, special:magic"

          # scroll through workspaces with mod + scroll
          "$mod, mouse_down, workspace, e+1"
          "$mod, mouse_up, workspace, e-1"
          # alternatively, scroll through workspaces with mod + brackets
          "$mod, bracketleft, workspace, e-1"
          "$mod, bracketright, workspace, e+1"

          ", XF86LaunchA, exec, ${screenshotScript}"
          ", XF86LaunchB, exec, ${lib.getExe pkgs.rofi-rbw-wayland} -a copy -t password --clear-after 20"

          "ALT, Tab, exec, ${lib.getExe pkgs.rofi-wayland} -show window"
        ] ++ (
          # workspaces
          # binds $mod + [shift +] {1..10} to [move to] workspace {1..10}
          builtins.concatLists (builtins.genList (
            x: let
              ws = let
                c = (x + 1) / 10;
              in
                builtins.toString (x + 1 - (c * 10));
            in [
              "$mod, ${ws}, workspace, ${toString (x + 1)}"
              "$mod SHIFT, ${ws}, movetoworkspace, ${toString (x + 1)}"
            ]
          )
          10)
        );

        input = {
          kb_layout = "us";

          touchpad = {
            disable_while_typing = false;
            natural_scroll = true;
          };

          follow_mouse = 1;

          sensitivity = 0; # -1.0 - 1.0, 0 means no modification
        };

        monitor=",highrr,auto,auto";

        exec-once = [ 
          "${lib.getExe pkgs.networkmanagerapplet}"                          # network applet
          "${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1" # polkit agent
          "${lib.getExe pkgs.wl-clip-persist} --clipboard regular"           # to fix wl clipboards disappearing
        ];

        env = [
          "XCURSOR_THEME,${config.modules.desktop.themes.cursorTheme.name}"
          "XCURSOR_SIZE,24"
        ];

        general = {
          gaps_in = 6;
          gaps_out = 6;
          border_size = 1;
          no_border_on_floating = false;

          layout = "dwindle";

          resize_on_border = true;	
        };

        windowrulev2 = [
          # common popups
          "float, class:org.gnome.FileRoller"
          "size 1100 650, class:org.gnome.FileRoller"
          "center, class:org.gnome.FileRoller"
          "float, class:org.gnome.Loupe"
          "size 1100 650, class:org.gnome.Loupe"
          "center class:org.gnome.Loupe"
          "float, class:com.gabm.satty"
          "size 1100 650, class:com.gabm.satty"
          "center 1100 650, class:com.gabm.satty"
          "float, initialTitle:^Open Folder$"
          "size 1100 650, initialTitle:^Open Folder$"
          "center, initialTitle:^Open Folder$"
          "float, initialTitle:^Open File$"
          "size 1100 650, initialTitle:^Open File$"
          "center, initialTitle:^Open File$"
          "float, initialTitle:^Open Files$"
          "size 1100 650, initialTitle:^Open Files$"
          "center, initialTitle:^Open Files$"
          "float, initialTitle:^Save As$"
          "size 1100 650, initialTitle:^Save As$"
          "center, initialTitle:^Save As$"
          "float, initialTitle:^Select a file to open$"
          "size 1100 650, initialTitle:^Select a file to open$"
          "center, initialTitle:^Select a file to open$"
          "float, initialTitle:^File Upload$"
          "size 1100 650, initialTitle:^File Upload$"
          "center, initialTitle:^File Upload$"

          "float, class:\.exe$"

          # fix focus
          "stayfocused, class:^gcr-prompter"
          "dimaround, class:^gcr-prompter"
          "stayfocused, class:^pinentry-"
          "dimaround, class:^pinentry-"
          "stayfocused, class:^polkit-"
          "dimaround, class:^polkit-"
          "stayfocused, class:^rofi-"

          # firefox pip
          "float, title:^Picture-in-Picture$"
          "pin, title:^Picture-in-Picture$"
          "noborder, title:^Picture-in-Picture$"
          "keepaspectratio, title:^Picture-in-Picture$"
          # discord pip
          "pin, initialTitle:^Discord Popout$"
          "float, initialTitle:^Discord Popout$"

          # workspace moving
          "workspace 1 silent, class:^firefox"
          "workspace 2 silent, class:code-url-handler"
          "workspace 4 silent, class:vesktop"
        ];

        blurls = [
          "gtk-layer-shell"
        ];

        layerrule = [
          "animation slide, notifications"
          "animation slide, waybar"
          "blur, notifications"
          "blur, wob"
        ];

        decoration = {
          rounding = 10;

          blur = {
            enabled = true;
            size = 4;
            passes = 2;
            popups = true;
          };

          drop_shadow = true;
          shadow_range = 4;
          shadow_render_power = 3;
        };

        animations = {
          enabled = true;

          bezier = [
            "outCubic, 0.33, 1, 0.68, 1"
            "outExpo, 0.16, 1, 0.3, 1"
          ];

          animation = [
            "windows, 1, 5, outExpo, popin"
            "windowsOut, 1, 5, outCubic, popin 80%"
            "border, 1, 2, outExpo"
            "fade, 1, 3, outCubic"
            "workspaces, 1, 6, outExpo"
            "specialWorkspace, 1, 2, outCubic, fade"
          ];
        };

        dwindle = {
          pseudotile = "yes"; # master swtich for pseudotiling. enabling is mod + P in the keybinds section
          preserve_split = "yes";
        };

        master = {
          new_status = "master";
        };

        gestures = {
          workspace_swipe = true;
        };

        misc = {
          force_default_wallpaper = 0;
          disable_splash_rendering = true;
          disable_hyprland_logo = true;

          initial_workspace_tracking = 0;
        };
      };
    };
  };
}
