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

with lib;
let
  cfg = config.my.programs.niri;
  inherit (config.home-manager.users.moritz.lib.niri) actions;
in
{
  options.my.programs.niri.enable = mkEnableOption "niri";
  options.my.programs.niri.autoStart = mkEnableOption "auto start niri" // {
    default = true;
  };

  config = mkIf cfg.enable {
    users.users.moritz.packages = with pkgs; [
      brightnessctl # control brightness
      grimblast # screenshot tool
      pamixer # pulse audio cli
      playerctl # control media playback
      slurp # region select for wayland (for screensharing)
      wdisplays # manage monitors
      wl-clipboard # clipboard tool for wayland
      wlr-randr
      jq
    ];

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

    programs.niri.enable = true;

    my = {
      programs = {
        wallpaper.enable = true;
        ghostty.enable = true;
        tofi.enable = true;
      };
      wallpapers.enable = true;
      services = {
        dunst.enable = true;
        wallpaper = {
          enable = true;
          target = "niri.service";
        };
        spotify-player.target = "niri.service";
      };
    };
    home-manager.users.moritz = {
      programs.waybar = {
        enable = true;

        # start using systemd service
        systemd = {
          enable = true;
          target = "niri.service";
        };

        settings = {
          mainBar = {
            start_hidden = true;
            layer = "top";
            position = "top";
            height = 20;
            modules-left = [ "niri/workspaces" ];
            modules-center = [ "niri/window" ];
            modules-right = [ "network" "memory" "cpu" "battery" "clock" ];
          };
        };
      };

      # lock screen after timeout
      programs.swaylock = {
        enable = true;
        settings = {
          color = "000000";
        };
      };
      services.swayidle = {
        enable = true;
        events = [
          {
            event = "before-sleep";
            command = "${lib.getExe pkgs.swaylock} -fF";
          }
          {
            event = "lock";
            command = "${lib.getExe pkgs.swaylock} -fF";
          }
        ];
        timeouts =
          let
            lockTimeout = 10;
          in
          [
            {
              timeout = lockTimeout * 60 - 10;
              command = "${pkgs.libnotify}/bin/notify-send 'Locking screen!'";
            }
            {
              timeout = lockTimeout * 60 + 10;
              command = "${pkgs.systemd}/bin/loginctl lock-session";
            }
          ];
        systemdTarget = "niri.service";
      };
      services.kanshi = {
        enable = true;
        systemdTarget = "niri.service";
      };
      programs.niri = {
        settings = {
          environment = {
            "NIXOS_OZONE_WL" = "1";
            "QT_QPA_PLATFORM" = "wayland";
          };
          binds = {
            # spawn different programs
            "Mod+Return".action.spawn = config.my.terminal.package;
            "Mod+Shift+escape".action.spawn = [ "loginctl" "lock-session" ];
            "Mod+R".action.spawn = "${lib.getExe pkgs.fuzzel}";

            # keyboard layout
            "Mod+Space".action = actions.switch-layout "next";

            "Mod+I".action = actions.show-hotkey-overlay;
            "Mod+Q".action = actions.close-window;
            "Mod+Shift+Q".action = actions.quit;
            "Mod+Shift+C".action = actions.screenshot;

            # resizing / swapping / switching
            "Mod+F".action = actions.fullscreen-window;

            "Mod+Shift+H".action.set-column-width = "-5%";
            "Mod+Shift+L".action.set-column-width = "+5%";

            "Mod+J".action = actions.focus-window-down-or-column-right;
            "Mod+K".action = actions.focus-window-up-or-column-left;

            "Mod+H".action = actions.move-column-left-or-to-monitor-left;
            "Mod+L".action = actions.move-column-right-or-to-monitor-right;

            "Mod+W".action.spawn = [ "pkill" "-USR1" "waybar" ];

            "Mod+C".action = actions.consume-window-into-column;
            "Mod+E".action = actions.expel-window-from-column;

            "Mod+comma".action = actions.focus-monitor-up;
            "Mod+period".action = actions.focus-monitor-down;

            "Mod+Shift+comma".action = actions.move-workspace-to-monitor-up;
            "Mod+Shift+period".action = actions.move-workspace-to-monitor-down;
            "Mod+T".action = actions.switch-preset-column-width;

            "Mod+Shift+1".action.move-window-to-workspace = 1;
            "Mod+Shift+2".action.move-window-to-workspace = 2;
            "Mod+Shift+3".action.move-window-to-workspace = 3;
            "Mod+Shift+4".action.move-window-to-workspace = 4;
            "Mod+Shift+5".action.move-window-to-workspace = 5;
            "Mod+Shift+6".action.move-window-to-workspace = 6;
            "Mod+Shift+7".action.move-window-to-workspace = 7;
            "Mod+Shift+8".action.move-window-to-workspace = 8;
            "Mod+Shift+9".action.move-window-to-workspace = 9;
            "Mod+Shift+0".action.move-window-to-workspace = 10;

            "Mod+1".action.focus-workspace = 1;
            "Mod+2".action.focus-workspace = 2;
            "Mod+3".action.focus-workspace = 3;
            "Mod+4".action.focus-workspace = 4;
            "Mod+5".action.focus-workspace = 5;
            "Mod+6".action.focus-workspace = 6;
            "Mod+7".action.focus-workspace = 7;
            "Mod+8".action.focus-workspace = 8;
            "Mod+9".action.focus-workspace = 9;
            "Mod+0".action.focus-workspace = 10;

            # audio
            "XF86_AudioMute".action.spawn = [ "wpctl" "set-mute" "@DEFAULT_AUDIO_SINK@" "toggle" ];
            "XF86AudioRaiseVolume".action.spawn = [ "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "5%+" "-l" "1.0" ];
            "XF86AudioLowerVolume".action.spawn = [ "wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "5%-" ];
            # TODO(mangoiv): mic mute toggle
          };
          environment = {
            DISPLAY = ":0";
          };
          layout = {
            border.enable = false;
            focus-ring.enable = false;
            default-column-width.proportion = 2.0 / 3.0;
            preset-column-widths = [
              { proportion = 1.0 / 3.0; }
              { proportion = 2.0 / 3.0; }
              { proportion = 1.0 / 1.0; }
            ];
            gaps = 3;
          };
          animations = {
            enable = true;
            slowdown = 0.5;
          };
          prefer-no-csd = true;
          hotkey-overlay.skip-at-startup = true;
          window-rules = [
            {
              matches = [
                { title = "^.*1Password.*$"; }
                { title = "^.*Bitwarden.*$"; }
                { title = "^.*KeePassXC.*$"; }
              ];
              block-out-from = "screen-capture";
            }
            {
              clip-to-geometry = true;
              geometry-corner-radius = {
                bottom-left = 5.0;
                bottom-right = 5.0;
                top-left = 5.0;
                top-right = 5.0;
              };
            }
          ];
          switch-events = {
            lid-close.action.spawn = [ "loginctl" "lock-session" ];
          };
          input = {
            touchpad.natural-scroll = false;
            focus-follows-mouse.enable = true;
            warp-mouse-to-focus = true;
            keyboard = {
              xkb.layout = "us, de";
            };
          };
        };
      };
    };

    systemd.user.services.xwayland-satellite = {
      description = "Xwayland outside your Wayland";
      after = [ "graphical-session.target" ];
      wantedBy = [ "graphical-session.target" ];
      partOf = [ "graphical-session.target" ];
      bindsTo = [ "graphical-session.target" ];
      requisite = [ "graphical-session.target" ];
      serviceConfig = {
        Type = "notify";
        Restart = "always";
        RestartSec = "1s";
        ExecStart = "${getExe pkgs.xwayland-satellite}";
        StandardOutput = "journal";
        NotifyAccess = "all";
      };
    };

    services = {
      dbus.enable = true;
      # use pipewire (needed for screensharing)
      pipewire = {
        enable = true;
        alsa.enable = true;
        pulse.enable = true;
      };
      displayManager = mkIf cfg.autoStart {
        autoLogin = {
          enable = true;
          user = "moritz";
        };
        defaultSession = "niri";
      };
      xserver = mkIf cfg.autoStart {
        enable = true;
        displayManager.lightdm.enable = true;
      };
    };
    security.rtkit.enable = true;
  };
}
