{
  config,
  pkgs,
  username,
  ...
}:
let
  volumeChange = pkgs.writeShellScript "volume-change" ''
    # FROM: https://github.com/jsimonrichard/nix-config/blob/master/modules/my-config/desktop/hyprland/home-manager/desktop/hyprland/keybinds.nix

    # Arbitrary but unique message tag
    msgTag="dunst-sound"

    # Change the volume using alsa(might differ if you use pulseaudio)
    wpctl $@ > /dev/null

    # Query wpctl for the current volume and whether or not the speaker is muted
    volume="$(wpctl get-volume $2 | awk '{print $2 * 100}')"
    mute="$(wpctl get-volume $2 | awk '{print $3}')"
    if [[ $volume == 0 || "$mute" == "[MUTED]" ]]; then
      # Show the sound muted notification
      dunstify -a "volumeChange" -u low -i audio-volume-muted -h string:x-dunst-stack-tag:$msgTag "Volume muted" 
    else
      # Show the volume notification
      dunstify -a "volumeChange" -u low -i audio-volume-high -h string:x-dunst-stack-tag:$msgTag \
      -h int:value:"$volume" "Volume: $volume%"
    fi
  '';
in
{
  home.packages = with pkgs; [
    dunst
    waybar
    swww
    rofi-wayland
    brightnessctl
    networkmanagerapplet
    grim
    grimblast
    swappy
    slurp
    wl-clipboard
    hyprpaper
    # (pkgs.waybar.overrideAttrs (oldAttrs: {
    #   mesonFlags = oldAttrs.mesonFlags ++ [ "-Dexperimental=true" ];
    # }))
  ];

  services.hyprpaper = {
    enable = true;
    settings = {
      ipc = false;
      splash = false;
      splash_offset = 5;
      splash_color = "rgb(ebdbb8)";

      preload = [ "$HOME/.nixos-config/backgrounds/island_1.jpg" ];
      wallpaper = [ ",$HOME/.nixos-config/backgrounds/island_1.jpg" ];
    };
  };

  programs.hyprlock = {
    enable = true;
    settings = {
      background = {
        monitor = "";
        # path = screenshot
        path = "$HOME/.nixos-config/backgrounds/island_2.jpg";
        color = "rgba(152, 179, 166, 0.9)";

        blur_passes = 1;
        blur_size = 7;
        noise = 1.17e-2;
        contrast = 0.8916;
        brightness = 0.8172;
        vibrancy = 0.1696;
        vibrancy_darkness = 0.0;
      };

      input-field = {
        monitor = "";
        size = "200, 50";
        outline_thickness = 3;
        dots_size = 0.33; # Scale of input-field height, 0.2 - 0.8
        dots_spacing = 0.15; # Scale of dots' absolute size, 0.0 - 1.0
        dots_center = true;
        dots_rounding = -1; # -1 default circle, -2 follow input-field rounding
        outer_color = "rgb(151515)";
        inner_color = "rgb(200, 200, 200)";
        font_color = "rgb(10, 10, 10)";
        fade_on_empty = true;
        fade_timeout = 1000; # Milliseconds before fade_on_empty is triggered.
        placeholder_text = ''<i>Input Password...</i>''; # Text rendered in the input box when it's empty.
        hide_input = false;
        rounding = -1; # -1 means complete rounding (circle/oval)
        check_color = "rgb(204, 136, 34)";
        fail_color = "rgb(204, 34, 34)"; # if authentication failed, changes outer_color and fail message color
        fail_text = "<i>$FAIL <b>($ATTEMPTS)</b></i>"; # can be set to empty
        fail_transition = 300; # transition time in ms between normal outer_color and fail_color
        capslock_color = -1;
        numlock_color = -1;
        bothlock_color = -1; # when both locks are active. -1 means don't change outer color (same for above)
        invert_numlock = false; # change color if numlock is off
        position = "0, 200";
        halign = "center";
        valign = "center";
      };

      label = [
        {
          monitor = "";
          text = "cmd[update:1000] echo \"$TIME\"";
          color = "rgba(200, 200, 200, 1.0)";
          font_size = 55;
          font_family = "JetBrainsMono Nerd Font";
          position = "0, 150";
          halign = "center";
          valign = "bottom";
          shadow_passes = 5;
          shadow_size = 10;
        }

        {
          monitor = "";
          text = "$USER";
          color = "rgba(200, 200, 200, 1.0)";
          font_size = 20;
          font_family = "JetBrainsMono Nerd Font";
          position = "0, 80";
          halign = "center";
          valign = "bottom";
          shadow_passes = 5;
          shadow_size = 10;
        }
      ];
    };
  };

  services.hypridle = {
    enable = true;
    settings = {
      general = {
        before_sleep_cmd = "loginctl lock-session";
        lock_cmd = "${pkgs.procps}/bin/pidof hyprlock || ${pkgs.hyprlock}/bin/hyprlock";
        # unlock_cmd = "loginctl unlock-session";
        after_sleep_cmd = "hyprctl dispatch dpms on && notify-send \"Back from idle.\" \"Welcome back!\"";
      };
      listener = [
        {
          timeout = 5;
          on-timeout = "pidof hyprlock && hyprctl dispatch dpms off";
          on-resume = "hyprctl dispatch dpms on";
        }
        {
          timeout = 150; # 2.5min.
          on-timeout = "light -O && light -S 10"; # set monitor backlight to minimum, avoid 0 on OLED monitor.
          on-resume = "light -I"; # monitor backlight restore.
        }
        {
          timeout = 300;
          on-timeout = "playerctl pause";
        }
        {
          timeout = 270;
          on-timeout = "notify-send \"Idle\" \"You're idle... locking in 30s.\"";
        }
        {
          timeout = 300; # 5min
          on-timeout = "loginctl lock-session"; # lock screen when timeout has passed
        }

        {
          timeout = 330; # 5.5min
          on-timeout = "hyprctl dispatch dpms off"; # screen off when timeout has passed
          on-resume = "hyprctl dispatch dpms on"; # screen on when activity is detected after timeout has fired.
        }

        {
          timeout = 1800; # 30min
          on-timeout = "systemctl suspend"; # suspend pc
        }
      ];
    };
  };

  wayland.windowManager.hyprland.enable = true;
  wayland.windowManager.hyprland.settings = {
    monitor = [
      "eDP-1,2560x1600@60.00Hz,0x0,1"
      "DP-3,preferred,-3840x-560,1"
      "DP-2,preferred,auto,1.5"
    ];
    "$mod" = "SUPER";

    input = {
      kb_options = "compose:rctrl,numpad:mac"; # workaround for split numpad https://github.com/hyprwm/Hyprland/issues/6886
      numlock_by_default = true;
    };
    exec-once = [
      "dunst"
      "waybar"
      "${pkgs.networkmanagerapplet}/bin/nm-applet --sm-disable --indicator"
      "blueman-applet"
      "${pkgs.libsForQt5.polkit-kde-agent}/libexec/polkit-kde-authentication-agent-1"
      "systemctl --user import-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP"
      "systemctl --user start hyprpaper.service" # they are enabled, but don't start because they try to start before WAYLAND_DISPLAY is set

    ];

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

    bind =
      [
        "$mod, F, exec, firefox"
        "$mod, k, exec, kitty"
        ", Print, exec, grimblast copy area"
        "$mod, l, exec, hyprlock" # Add a keybinding to lock the screen
        "$mod, C, exec, code"
        "$mod, P, exec, sleep 2; grim -g \"$(slurp)\" - | swappy -f -"
        "$mod, E, exec, hyprctl dispatch exit"
        "$mod, r, exec, rofi -show run"
        "$mod, code:51, exec, 1password" # super + \
        "$mod, W, togglefloating,"
        ",XF86MonBrightnessDown, exec, brightnessctl s 5%-"
        ",XF86MonBrightnessUp,   exec, brightnessctl s +5%"
      ]
      ++ (
        # 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
        )
      );
    windowrulev2 = [
      # https://jbmorley.co.uk/posts/2024-02-13-1password-and-hyprland/
      "float, title:(1Password)"
      "size 70% 70%, title:(1Password)"
      "center, title:(1Password)"

      "float,class:(.blueman-manager-wrapped)"
      "size 25% 25%,class:(.blueman-manager-wrapped)"

      "float,class:(org.kde.polkit-kde-authentication-agent-1)"
      "opacity 0.80 0.70,class:^(org.kde.polkit-kde-authentication-agent-1)$"
      "bordercolor rgba(ed8796FF), class:org.kde.polkit-kde-authentication-agent-1"
      "dimaround, class:org.kde.polkit-kde-authentication-agent-1"
      "stayfocused, class:org.kde.polkit-kde-authentication-agent-1"

      # nextcloud
      "float,class:(com.nextcloud.desktopclient.nextcloud)"
      "size 400 800,class:(com.nextcloud.desktopclient.nextcloud)"
      "move 100%-412 44,class:(com.nextcloud.desktopclient.nextcloud)"
      # to try if it has sideeffects
      "noinitialfocus, initialClass:com.nextcloud.desktopclient.nextcloud"

      "noinitialfocus, initialClass:atlassify"
    ];
    # Bind flags
    # l -> locked, will also work when an input inhibitor (e.g. a lockscreen) is active.
    # r -> release, will trigger on release of a key.
    # e -> repeat, will repeat when held.
    # n -> non-consuming, key/mouse events will be passed to the active window in addition to triggering the dispatcher.
    # m -> mouse, see below
    # t -> transparent, cannot be shadowed by other binds.
    # i -> ignore mods, will ignore modifiers.
    binde = [
      ", XF86AudioRaiseVolume, exec, ${volumeChange} set-volume @DEFAULT_AUDIO_SINK@ 5%+ --limit 1.3"
      "CTRL, XF86AudioRaiseVolume, exec, ${volumeChange} set-volume @DEFAULT_AUDIO_SOURCE@ 5%+ --limit 1"
    ];
    bindle = [
      ", XF86AudioLowerVolume, exec, ${volumeChange} set-volume @DEFAULT_AUDIO_SINK@ 5%-"
      "CTRL, XF86AudioLowerVolume, exec, ${volumeChange} set-volume @DEFAULT_AUDIO_SOURCE@ 5%-"
    ];
    bindl = [
      ", XF86AudioMute,        exec, ${volumeChange} set-mute   @DEFAULT_AUDIO_SINK@ toggle"
    ];
  };
}
