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


let
  inherit (lib) mkEnableOption mkIf mkOption types;

  cfg = config.my.programs.river;
in
{
  options.my.programs.river = {
    enable = mkEnableOption "river";
    keyboardLayouts = mkOption {
      type = types.listOf types.str;
      description = "list of keyboard layouts";
      default = [ "us" "de" ];
    };
    nvidiaSupport = mkEnableOption "nvidiaSupport";
  };

  config = mkIf cfg.enable {
    programs.river.enable = true;
    my = {
      programs = {
        wallpaper.enable = true;
        kitty.enable = true;
        tofi.enable = true;
      };
      wallpapers.enable = true;
      services = {
        dunst.enable = true;
        wallpaper = {
          enable = true;
          target = "river-session.target";
        };
        spotify-player.target = "river-session.target";
      };
    };

    home-manager.users.moritz = {
      home.packages = with pkgs; [
        rivercarro
        wlr-randr
        jq
      ];
      services.kanshi = {
        enable = true;
        systemdTarget = "river-session.target";
      };
      wayland.windowManager.river = {
        enable = true;
        settings = {
          border-width = 2;
          declare-mode = [
            "locked"
            "normal"
            "passthrough"
          ];
          map-switch.normal.lid = {
            close = ''
              spawn 'wlr-randr --output eDP-1 --off; monitors=$(wlr-randr --json | jq .[].name | count); [ "$monitors" = 1] && loginctl lock-session'
            '';
            open = "spawn 'wlr-randr --output eDP-1 --on'";
          };
          map = {
            normal = {
              "Super Q" = "close";
              "Super Return" = "spawn '${config.my.terminal.package}'";
              "Super R" = ''spawn 'exec $(tofi-run --fuzzy-match=true)' '';
              "Super W" = ''spawn "pkill -USR1 waybar"'';
              "Super+Shift R" = "spawn ~/.config/river/init";

              # Focus view
              "Super J" = "focus-view next";
              "Super K" = "focus-view previous";

              # swap the focused view
              "Super+Shift J" = "swap next";
              "Super+Shift K" = "swap previous";

              # focus output
              "Super Period" = "focus-output next";
              "Super Comma" = "focus-output previous";

              # send to output
              "Super+Shift Period" = "send-to-output next";
              "Super+Shift Comma" = "send-to-output previous";

              # bump in layout stack
              "Super Z" = "zoom";

              # lock screen
              "Super+Alt L" = ''spawn "loginctl lock-session"'';
              "Control I" = ''spawn "loginctl lock-session"'';

              # XF86 keys
              "None XF86AudioLowerVolume" = "spawn 'pamixer -d 5'";
              "None XF86AudioRaiseVolume" = "spawn 'pamixer -i 5'";
              "None XF86AudioMute" = "spawn 'pamixer -t'";
              "None XF86AudioNext" = "spawn 'playerctl -p spotifyd,firefox next'";
              "None XF86AudioPlay" = "spawn 'playerctl -p spotifyd,firefox play-pause'";
              "None XF86AudioPrev" = "spawn 'playerctl -p spotifyd,firefox previous'";
            } //
            # tags
            (
              let
                numbers = lib.range 1 9;
                toTag = num: "$((1 << (${toString num} - 1)))";

                mkMappings = num:
                  let
                    numStr = toString num;
                    tag = toTag num;
                  in
                  [
                    # Super+Control+[1-9] to toggle focus of tag [0-8]
                    { name = "Super ${numStr}"; value = "set-focused-tags ${tag}"; }

                    # Super+Shift+Control+[1-9] to toggle tag [0-8] of focused view
                    { name = "Super+Shift ${numStr}"; value = "toggle-view-tags ${tag}"; }
                  ];
                mappings = lib.flatten (map mkMappings numbers);
              in
              lib.listToAttrs mappings
            );
          };
          map-pointer.normal = {
            "Super BTN_LEFT" = "move-view";
            "Super BTN_RIGHT" = "resize-view";
            "Super BTN_MIDDLE" = "toggle-float";
          };
          attach-mode = "bottom";
          default-layout = "rivercarro";
          focus-follows-cursor = "normal";
          hide-cursor = {
            timeout = "1500";
            when-typing = "enabled";
          };
          set-cursor-warp = "on-focus-change";
          keyboard-layout = "-options grp:win_space_toggle,caps:escape ${lib.concatStringsSep "," cfg.keyboardLayouts}";
        };
        extraConfig = /* bash */ ''
          rivercarro_pid="$(pidof rivercarro)"
          if [[ -z $rivercarro_pid ]]; then
            rivercarro -inner-gaps 4 -outer-gaps 4 &
          fi
        '';
      };

      # add waybar as a status bar
      programs.waybar = {
        enable = true;

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

        settings = {
          mainBar = {
            start_hidden = true;
            layer = "top";
            position = "top";
            height = 20;
            modules-left = [ "river/tags" ];
            modules-center = [ "river/window" ];
            modules-right = [ "network" "memory" "cpu" "battery" "clock" ];
          };
        };
        style = lib.readFile ./style.css;
      };

      # 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 = "river-session.target";
      };
    };

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

    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
    ];


    # additional environment variables
    environment.sessionVariables =
      {
        XDG_CURRENT_DESKTOP = "river";
        XDG_SESSION_TYPE = "wayland";
        XDG_SESSION_DESKTOP = "river";
        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";
      } // (lib.optionalAttrs cfg.nvidiaSupport
        {
          GBM_BACKEND = "nvidia-drm";
          GDK_BACKEND = "wayland";
          LIBVA_DRIVER_NAME = "nvidia";
          MOZ_ENABLE_WAYLAND = "1";
          WLR_DRM_DEVICES = "/dev/dri/card0";
          WLR_DRM_NO_ATOMIC = "1";
          WLR_NO_HARDWARE_CURSORS = "1";
          XDG_CURRENT_DESKTOP = "river";
          _GL_GSYNC_ALLOWED = "0";
          __GLX_VENDOR_LIBRARY_NAME = "nvidia";
          __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;
      };
      displayManager = {
        autoLogin = {
          enable = true;
          user = "moritz";
        };
        defaultSession = "river";
      };
      xserver = {
        enable = true;
        displayManager.lightdm.enable = true;
      };
    };
    security.rtkit.enable = true;
  };
}