{ lib, config, inputs, pkgs, ... }:
{
  imports = [
    ../../common/desktop
  ];

  home.packages = with pkgs; [
    grimblast
    pamixer
    playerctl
  ];

  wayland.windowManager.hyprland = {
    enable = true;
    systemd = {
      enable = true;
    };

    settings = {
      general = {
        gaps_in = 15;
        gaps_out = 20;
        border_size = 1;
      };
      cursor.inactive_timeout = 4;

      device = [
        {
          name = "royuan-akko-keyboard";
          kb_layout = "us_intl";
        }
      ];

      dwindle = {
        split_width_multiplier = 1.35;
        pseudotile = true;
      };

      layerrule = [
        "animation fade,hyprpicker"
        "animation fade,selection"
        "blur,^(wofi)$"
        "ignorezero,^(wofi)$"
      ];

      decoration = {
        active_opacity = 1.0;
        inactive_opacity = 0.85;
        fullscreen_opacity = 1.0;
        rounding = 7;
        blur = {
          enabled = true;
          size = 4;
          passes = 3;
          new_optimizations = true;
          ignore_opacity = true;
          popups = true;
        };
        drop_shadow = true;
        shadow_range = 12;
        shadow_offset = "3 3";
      };

      animations = {
        enabled = true;
        bezier = [
          "easein,0.1, 0, 0.5, 0"
          "easeinback,0.35, 0, 0.95, -0.3"

          "easeout,0.5, 1, 0.9, 1"
          "easeoutback,0.35, 1.35, 0.65, 1"

          "easeinout,0.45, 0, 0.55, 1"
        ];

        animation = [
          "fadeIn,1,3,easeout"
          "fadeLayersIn,1,3,easeoutback"
          "layersIn,1,3,easeoutback,slide"
          "windowsIn,1,3,easeoutback,slide"

          "fadeLayersOut,1,3,easeinback"
          "fadeOut,1,3,easein"
          "layersOut,1,3,easeinback,slide"
          "windowsOut,1,3,easeinback,slide"

          "border,1,3,easeout"
          "fadeDim,1,3,easeinout"
          "fadeShadow,1,3,easeinout"
          "fadeSwitch,1,3,easeinout"
          "windowsMove,1,3,easeoutback"
          "workspaces,1,2.6,easeoutback,slide"
        ];
      };

      bindm = [
        "SUPER,mouse:272,movewindow"
        "SUPER,mouse:273,resizewindow"
      ];

      bind = let
        terminal = "${pkgs.alacritty}/bin/alacritty";
        grimblast = lib.getExe pkgs.grimblast;
        workspaces = [
          "1"
          "2"
          "3"
          "4"
          "5"
        ];
        directions = rec {
          left = "l";
          right = "r";
          up = "u";
          down = "d";
          h = left;
          l = right;
          k = up;
          j = down;
        };
      in [
        "SUPER,Return,exec,${terminal}"
        "SUPERSHIFT,q,killactive" # exit program
        "SUPERSHIFT,e,exit" # exit hyprland
        "SUPERSHIFT,r,exec,hyprctl reload" # reload currently running hyprland

        "SUPER,s,togglesplit" # horizontal split
        "SUPER,f,fullscreen,1" # borderless window
        "SUPERSHIFT,f,fullscreen,0" # proper fullscreen
        "ALTSHIFT,space,togglefloating" # floating window

        "SUPER,minus,splitratio,-0.25" # split gets slightly smaller
        "SUPERSHIFT,minus,splitratio,-0.3333333" # split gets smaller
        "SUPER,equal,splitratio,0.25" # split gets slightly larger
        "SUPERSHIFT,equal,splitratio,0.3333333" # split gets larger

        "SUPER,g,togglegroup" # make a window group
        "SUPER,t,lockactivegroup,toggle" # lock/unlock the current group
        "SUPER,tab,changegroupactive,f" # switch to next window in group
        "SUPERSHIFT,tab,changegroupactive,p" # switch to prev window in group
        
        "SUPER,dead_grave,workspace,previous" # prev workspace
        "SUPER,dead_grave,workspace,next" # next workspace

        "SUPER,u,togglespecialworkspace" # toggle special workspace
        "SUPERSHIFT,u,movetoworkspacesilent,special" # move to special workspace

        ",Print,exec,${grimblast} --notify --freeze copy area" # screenshot area
        "SHIFT,Print,exec,${grimblast} --notify --freeze copy output" # screenshot all

        ",XF86AudioRaiseVolume,exec,pamixer -i 5" # raise volume
        ",XF86AudioLowerVolume,exec,pamixer -d 5" # lower volume
        ",XF86AudioPlay,exec,playerctl play-pause" # play/pause
        ",XF86AudioNext,exec,playerctl next" # next song
        ",XF86AudioPrev,exec,playerctl previous" # previous song
      ]
      ++
      # change workspace
      (map (n: "SUPER,${n},workspace,name:${n}") workspaces)
      ++
      # move window to workspace
      (map (n: "SUPERSHIFT,${n},movetoworkspacesilent,name:${n}") workspaces)
      ++
      # move focus
      (lib.mapAttrsToList (key: direction: "SUPER,${key},movefocus,${direction}") directions)
      ++
      # swap windows
      (lib.mapAttrsToList (key: direction: "SUPERSHIFT,${key},swapwindow,${direction}") directions)
      ++
      # move windows
      (lib.mapAttrsToList (key: direction: "SUPERCONTROL,${key},movewindoworgroup,${direction}") directions)
      ++
      # launcher
      (
        let
          wofi = lib.getExe pkgs.wofi;
        in 
          lib.optionals config.programs.wofi.enable [
            "SUPER,Space,exec,${wofi} -S drun -W 20% -H 15%"
            "SHIFTSUPER,Space,exec,${wofi} -S run -W 20% -H 15%"
          ]
      );

      monitor = map (
        m: "${m.name},${
        if m.enabled
          then "${toString m.width}x${toString m.height}@${toString m.refreshRate},${m.position},1"
        else "disable"
      }"
      ) config.monitors;

      workspace = map (m: "name:${m.workspace},monitor:${m.name}") (
        lib.filter (m: m.enabled && m.workspace != null) config.monitors
      );
    };
  };
}