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

let
  cfg = config.sydnix.users.crumb.niri;
in {
  options.sydnix.users.crumb.niri = {
    enable = lib.mkEnableOption "Niri, à la crumb";
    wallpaper = lib.mkOption {
      type = lib.types.nullOr lib.types.path;
      default = config.stylix.image;
    };
    # xwayland-satellite implements rootless Xwayland in a separate application,
    # without the host compositor's involvement. It makes X11 windows appear as
    # normal windows, just like a native Xwayland integration. While it is still
    # somewhat experimental, it handles a lot of applications correctly, like
    # Steam, games and Discord.
    xwayland-satellite.enable =
      lib.mkEnableOption "xwayland-satellite starting with Niri"
        // { default = true; };
    polkit.enable =
      lib.mkEnableOption "Niri/Gnome Polkit" // { default = true; };
    swaylock.enable =
      lib.mkEnableOption "Niri Swaylock" // { default = true; };
    portal.enable =
      lib.mkEnableOption "Niri Portal" // { default = true; };
    gammastep.enable =
      lib.mkEnableOption "Niri gammastep" // { default = true; };
    swaync.enable =
      lib.mkEnableOption "Niri Sway Notification Center" // { default = true; };
    binds = lib.mkOption {
      type = lib.types.anything;
      default = {};
    };
  };

  config = lib.mkIf cfg.enable {
    # Enable the XDG portal, an interface for programs to request
    # permissions/resources.  This is necessary to screen-cast on
    # Wayland/Pipewire.
    #
    # See
    # https://github.com/YaLTeR/niri/wiki/Important-Software#portals.
    # Niri's NixOS module automatically brings in
    # xdg-desktop-portal-gnome and gnome-keyring.
    xdg.portal = lib.mkIf cfg.portal.enable {
      enable = true;
      xdgOpenUsePortal = true;

      extraPortals = [
        pkgs.xdg-desktop-portal-gtk
        pkgs.xdg-desktop-portal-gnome
      ];

      # Use xdg-desktop-portal-gtk by default, but fallback to
      # xdg-desktop-portal-gnome for screenshots and screen-casts,
      # two important features unsupported by the GTK
      # implementation.  See implementations and their supported
      # interfaces at
      # https://wiki.archlinux.org/title/XDG_Desktop_Portal.
      config.niri = {
        default = [ "gtk" ];
        "org.freedesktop.impl.portal.Screenshot" = [ "gnome" ];
        "org.freedesktop.impl.portal.ScreenCast" = [ "gnome" ];
      };
    };

    stylix.targets.swaylock.enable = cfg.swaylock.enable;

    services.polkit-gnome.enable = cfg.polkit.enable;

    # File-picker.
    home.packages = [ pkgs.nautilus ];

    systemd.user.services.xwayland-satellite =
      lib.mkIf cfg.xwayland-satellite.enable {
        Service.ExecStart =
          ["${pkgs.xwayland-satellite}/bin/xwayland-satellite"];
        Unit.After = ["niri.service"];
        Unit.PartOf = ["niri.service"];
        Install.WantedBy = ["niri.service"];
      };

    programs.niri = {
      settings = {
        # Activates some Nixpkgs patches to help run Electron applications under
        # Wayland.
	environment = {
	  NIXOS_OZONE_WL = "1";
	  DISPLAY = ":0";
	  XDG_CURRENT_DESKTOP = "niri";
	  QT_QPA_PLATFORM = "wayland";
	  ELECTRON_OZONE_PLATFORM_HINT = "auto";
	  QT_QPA_PLATFORMTHEME = "gtk3";
	  QT_QPA_PLATFORMTHEME_QT6 = "gtk3";
	};

	spawn-at-startup =
	  lib.optional cfg.swaync.enable
	    { command = [ "${pkgs.swaynotificationcenter}/bin/swaync" ]; }
	  ++ lib.optional cfg.gammastep.enable
	    { command = [ "${pkgs.gammastep}/bin/gammastep" "-o" "-O" "4000k"
	      "-b" "0.9:0.9" "-l" "0:0"]; }
	  ++ lib.optional
	    (! builtins.isNull cfg.wallpaper)
	    { command = [ "${pkgs.wbg}/bin/wbg" "${cfg.wallpaper}" ]; };

        input = {
          keyboard.xkb = {
	    layout = "us";
	    options = "ctrl:swapcaps,compose:menu,compose:ralt";
          };
          mouse = {
	    accel-speed = -0.5;
	    accel-profile = "flat";
          };
          touchpad = {
	    # Disable while typing.
	    dwt = true;
          };
          focus-follows-mouse.enable = true;
        };
        # Laptop fruitbook display.
        outputs."eDP-1" = {
          mode.width = 2560;
          mode.height = 1600;
          mode.refresh = 59.972;
          scale = 1.4;
        };
        # Desktop sydpc monitor.
        outputs."DP-1" = {
          mode.width = 2560;
          mode.height = 1440;
          mode.refresh = 143.912;
          scale = 1;
        };
        layout = {
          background-color = "transparent";
          gaps = 8;
          center-focused-column = "never";
          preset-column-widths = [ 
	    { proportion = 1.0 / 3.0; }
	    { proportion = 1.0 / 2.0; }
	    { proportion = 2.0 / 3.0; }
          ];
          default-column-width.proportion = 0.5;
          focus-ring = {
	    enable = false;
	    width = 2;
          };
          border = {
	    enable = true;
	    width = 2;
	    # Override Niri's Stylix integration.  Default uses Crystal Blue
	    # (from the Kanagawa palette); we override it with Old White.
	    active.color = config.lib.stylix.colors.withHashtag.base06;
          };
          shadow = {
	    enable = true;
	    softness = 30;
	    spread = 5;
	    offset.x = 5;
	    offset.y = 5;
          };
          tab-indicator = {
	    place-within-column = true;
	    position = "top";
	    # active.color = config.lib.stylix.colors.withHashtag.blue;
	    inactive.color = config.lib.stylix.colors.withHashtag.base01;
	    width = 8;
	    corner-radius = 2.0;
	    gaps-between-tabs = 10;
          };
        };
        prefer-no-csd = true;
        screenshot-path = "~/Pictures/Screenshots/%Y-%m-%d %H-%M-%S.png";
        cursor = {
          theme = "default";
          size = 24;
        };
        window-rules = [
          { # Set red borders to indicate that a window is being captured.
	    matches = [
	      { is-window-cast-target = true; }
	    ];
	    focus-ring = {
	      enable = true;
	      width = 2;
	      active.color = "#f38ba8";
	      inactive.color = "#7d0d2d";
	    };
	    border = {
	      width = 2;
	      inactive.color = "#7d0d2d";
	      active.color = "#7d0d2d";
	    };
	    shadow = {
	      color = "#7d0d2d70";
	      softness = 30;
	      spread = 10;
	      offset.x = 0;
	      offset.y = 0;
	    };
	    tab-indicator = {
	      active.color = "#f38ba8";
	      inactive.color = "#7d0d2d";
	    };
          }
          { # Block private DMs from screencast...
	    matches = [
	      { title = "Element.*\\|"; }
	      { title = "Discord.*@"; }
	    ];
	    excludes = [
	      # ... except when explicitly targeting the window.
	      { is-window-cast-target = true; }
	    ];
	    block-out-from = "screen-capture";
          }
          {
	    # This regular expression is intentionally made as specific as
	    # possible, since this is the default config, and we want no false
	    # positives.  You can get away with just app-id="wezterm" if you
	    # want.
	    matches = [
	      { app-id = "^org\\.wezfurlong\\.wezterm$"; }
	    ];
	    default-column-width = {};
          }
          {
	    # Floating windows.
	    matches = [
	      # Open the Firefox picture-in-picture player as floating by default.
	      { app-id = "firefox$"; title = "^Picture-in-Picture$"; }
	      # Gimp pop-ups.
	      {
                app-id = "^Gimp$";
                title = "^(New Layer|Change Foreground Color|Save Image)$";
	      }
	    ];
	    open-floating = true;
          }
          { # Start with low width.
	    matches = [
	      { app-id = "com\\.mitchellh\\.ghostty"; }
	    ];
	    default-column-width.proportion = 1.0 / 3.0;
          }
          {
	    matches = [
	      { app-id = "^emacs$"; }
	    ];
	    default-column-width.fixed = 640;
          }
          {
	    # Enable rounded corners for all windows.
	    geometry-corner-radius =
	      let r = 8.0;
	      in {
                bottom-left = r;
                top-left = r;
                bottom-right = r;
                top-right = r;
	      };
	    clip-to-geometry = true;
          }
        ];
        binds = {
          "Mod+Q".action.close-window = [];
          "Mod+Shift+Q".action.quit = [];
          "Mod+Ctrl+L".action.spawn = ["${pkgs.swaylock}/bin/swaylock"];
          "Mod+D".action.spawn = ["${pkgs.fuzzel}/bin/fuzzel"];
          "Mod+Shift+Slash".action.show-hotkey-overlay = [];

          # Powers off the monitors.  They will be powered back on upon any
          # keyboard/mouse input.
          "Mod+Shift+P".action.power-off-monitors = []; 

          "Mod+I".action.set-dynamic-cast-window = [];
          "Mod+Shift+I".action.set-dynamic-cast-monitor = [];
          "Mod+Ctrl+I".action.clear-dynamic-cast-target = [];

          "Mod+BracketLeft".action.consume-or-expel-window-left = [];
          "Mod+BracketRight".action.consume-or-expel-window-right = [];
          "Mod+Comma".action.consume-window-into-column = [];
          "Mod+Period".action.expel-window-from-column = [];

          "Mod+Minus".action.set-column-width = ["-10%"];
          "Mod+Equal".action.set-column-width = ["+10%"];

          "Mod+Shift+Minus".action.set-window-height = ["-10%"];
          "Mod+Shift+Equal".action.set-window-height = ["+10%"];

          "Mod+C".action.center-column = [];
          "Mod+M".action.maximize-column = [];
          "Mod+Shift+M".action.fullscreen-window = [];
          "Mod+Ctrl+M".action.toggle-windowed-fullscreen = [];

          "Mod+Shift+S".action.screenshot = [];
          "Print".action.screenshot-screen = [];
          "Mod+Print".action.screenshot-window = [];

          "Mod+X".action.spawn = ["ghostty"];
	  "Mod+E".action.spawn = ["emacsclient" "-c"];
	  "Mod+O".action.toggle-overview = [];

          "Mod+Shift+F".action.toggle-window-floating = []; 
          "Mod+F".action.switch-focus-between-floating-and-tiling = [];
          "Mod+Shift+T".action.toggle-column-tabbed-display = []; 

          "Alt+Tab".action.focus-window-previous = [];

          "Mod+H".action.focus-column-left = [];
          "Mod+J".action.focus-window-down = [];
          "Mod+K".action.focus-window-up = [];
          "Mod+L".action.focus-column-right = [];

          "Mod+Shift+H".action.move-column-left = []; 
          "Mod+Shift+J".action.move-window-down = []; 
          "Mod+Shift+K".action.move-window-up = []; 
          "Mod+Shift+L".action.move-column-right = []; 

          "XF86MonBrightnessDown".action.spawn =
	    [(lib.getExe pkgs.brightnessctl) "s" "5%-"];
          "XF86MonBrightnessUp".action.spawn =
	    [(lib.getExe pkgs.brightnessctl) "s" "+5%"];

          "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+Shift+1".action.move-column-to-workspace = [1];
          "Mod+Shift+2".action.move-column-to-workspace = [2];
          "Mod+Shift+3".action.move-column-to-workspace = [3];
          "Mod+Shift+4".action.move-column-to-workspace = [4];
          "Mod+Shift+5".action.move-column-to-workspace = [5];
          "Mod+Shift+6".action.move-column-to-workspace = [6];
          "Mod+Shift+7".action.move-column-to-workspace = [7];
          "Mod+Shift+8".action.move-column-to-workspace = [8];
          "Mod+Shift+9".action.move-column-to-workspace = [9];

          "Mod+Shift+R".action.switch-preset-window-height = [];
          "Mod+Ctrl+R".action.reset-window-height = [];

          "XF86AudioRaiseVolume".action.spawn =
	    ["wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.05+"];
          "XF86AudioLowerVolume".action.spawn =
	    ["wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.05-"];
        } // cfg.binds;

        layer-rules = [
          # Don't move wallpaper with workspace.
          {
	    matches = [{ namespace = "^wallpaper$"; }];
	    place-within-backdrop = true;
          }
        ];

        # debug = {
        #   wait-for-frame-completion-in-pipewire = {};
        # };
      };
    };
  };
}

