# settings/hyprland.nix
{ config, pkgs, lib, inputs, ... }:
let
  hyprland-pkgs = inputs.hyprland.packages.${pkgs.stdenv.hostPlatform.system};
  anyrun-pkgs   = inputs.anyrun.packages.${pkgs.stdenv.hostPlatform.system};

  isMacbook = config.networking.hostName == "FredOS-Macbook";
  isGaming  = !isMacbook;

in
{
  config = lib.mkIf (lib.elem config.networking.hostName [ "FredOS-Gaming" "FredOS-Macbook" ]) {
    programs.hyprland = {
      enable = true;
      xwayland.enable = true;
      package       = hyprland-pkgs.hyprland;
      portalPackage = hyprland-pkgs.xdg-desktop-portal-hyprland;
    };

    xdg.portal = {
      enable = true;
      # xdg-desktop-portal-hyprland is registered automatically by
      # programs.hyprland.portalPackage; listing it here too produced a
      # duplicate user-unit symlink during nixos-rebuild.
      extraPortals = with pkgs; [
        xdg-desktop-portal-gtk
      ];
      config.hyprland.default = [ "hyprland" "gtk" ];
    };

    security.polkit.enable = true;

    # Polkit GUI agent for GUI sudo prompts under Hyprland
    systemd.user.services.polkit-gnome-authentication-agent-1 = {
      description = "polkit-gnome-authentication-agent-1";
      wantedBy = [ "graphical-session.target" ];
      partOf = [ "graphical-session.target" ];
      after = [ "graphical-session.target" ];
      serviceConfig = {
        Type = "simple";
        ExecStart = "${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1";
        Restart = "on-failure";
      };
    };

    environment.systemPackages = with pkgs; [
      ghostty
      mako
      grim
      slurp
      wl-clipboard
      cliphist
      brightnessctl
      swayosd
      playerctl
      hyprpaper
      hyprlock
      hypridle
      hyprshot
      networkmanagerapplet
      pavucontrol
      polkit_gnome
    ];

    # Use upstream anyrun flake's HM module instead of the built-in one
    # for working daemon mode.
    home-manager.sharedModules = [
      ({ modulesPath, ... }: {
        disabledModules = [ "${modulesPath}/programs/anyrun.nix" ];
      })
      inputs.anyrun.homeManagerModules.default
    ];

    home-manager.users.fred = { config, lib, pkgs, inputs, ... }:
    let
      c    = config.lib.stylix.colors;
      rgb  = hex: "rgb(${hex})";
      rgba = hex: a: "rgba(${hex}${a})";
    in {
      # Stylix's Hyprland target injects settings.{general,decoration,group,misc}
      # as top-level keys, which render as hl.general()/hl.decoration()/… in Lua
      # mode — functions that don't exist.  Disable it and absorb the colours
      # into settings.config below.
      stylix.targets.hyprland.enable = false;

      # The disabled Hyprland target would normally enable this; do it
      # manually.  Stylix's hyprpaper target (auto-enabled) still handles
      # preload/wallpaper settings.
      services.hyprpaper.enable = true;

      wayland.windowManager.hyprland = {
        enable = true;
        configType = "lua";
        systemd.variables = [ "--all" ];
        package = hyprland-pkgs.hyprland;

        settings = {
          # hl.config({...}) — all static named-section configuration.
          # monitor is set per-host in hosts/FredOS-{Gaming,Macbook}.nix.
          config = {
            general = {
              gaps_in = 6;
              gaps_out = 12;
              border_size = 2;
              layout = "dwindle";
              resize_on_border = true;
              "col.active_border"   = rgb c.base0D;
              "col.inactive_border" = rgb c.base03;
            };

            decoration = {
              rounding = 8;
              blur = {
                enabled = true;
              };
              shadow.color = rgba c.base00 "99";
            };

            group = {
              "col.border_active"        = rgb c.base0D;
              "col.border_inactive"      = rgb c.base03;
              "col.border_locked_active" = rgb c.base0C;
              groupbar = {
                text_color    = rgb c.base05;
                "col.active"  = rgb c.base0D;
                "col.inactive" = rgb c.base03;
              };
            };

            render = {
              direct_scanout = false;
            };

            animations = {
              enabled = true;
            };

            input = {
              kb_layout = "gb,no";
              kb_options = "grp:alt_shift_toggle";
              follow_mouse = 1;
              accel_profile = "flat";
              sensitivity = 0;
            } // lib.optionalAttrs isMacbook {
              touchpad = {
                tap_to_click = true;
                tap_button_map = "lrm";
                natural_scroll = true;
              };
            };

            cursor = {
              no_warps = true;
            };

            dwindle = {
              preserve_split = true;
            };

            misc = {
              disable_hyprland_logo = true;
              disable_splash_rendering = true;
              # Apps demanding attention don't get to yank focus — they'll
              # show as urgent in the bar instead.
              focus_on_activate = false;
              vrr = 2;
              background_color = rgb c.base00;
            };

            # vfr moved from misc: to debug: in 0.55.0
            debug = {
              vfr = false; # keep compositor ticking, don't idle between frames
              disable_logs = false;
            };
          };
        };

        extraConfig =
          let
            powerMenu = pkgs.writeShellScript "power-menu" ''
              # Stop the daemon so standalone stdin mode can run cleanly.
              # systemd restarts it automatically afterwards (Restart=on-failure).
              systemctl --user stop anyrun.service 2>/dev/null || true
              choice=$(printf '%s\n' \
                $'\uf023  Lock' \
                $'\uf08b  Logout' \
                $'\uf01e  Reboot' \
                $'\uf011  Shutdown' \
                | ${anyrun-pkgs.anyrun}/bin/anyrun \
                    --plugins "${anyrun-pkgs.stdin}/lib/libstdin.so" \
                    --show-results-immediately true \
                    --hide-plugin-info true \
                    --close-on-click true)
              # Restart the daemon service (reset-failed clears the start-rate limiter).
              systemctl --user reset-failed anyrun.service 2>/dev/null
              systemctl --user start anyrun.service 2>/dev/null
              case "$choice" in
                *Lock)     ${pkgs.hyprlock}/bin/hyprlock ;;
                *Logout)   hyprctl dispatch exit ;;
                *Reboot)   systemctl reboot ;;
                *Shutdown) systemctl poweroff ;;
              esac
            '';
            kbdBrightUp = pkgs.writeShellScript "kbd-bright-up" ''
              ${pkgs.brightnessctl}/bin/brightnessctl -d smc::kbd_backlight set +10%
              brightness=$(${pkgs.brightnessctl}/bin/brightnessctl -d smc::kbd_backlight get)
              max=$(${pkgs.brightnessctl}/bin/brightnessctl -d smc::kbd_backlight max)
              echo $(( brightness * 100 / max )) > "$XDG_RUNTIME_DIR/wob.fifo"
            '';
            kbdBrightDown = pkgs.writeShellScript "kbd-bright-down" ''
              ${pkgs.brightnessctl}/bin/brightnessctl -d smc::kbd_backlight set 10%-
              brightness=$(${pkgs.brightnessctl}/bin/brightnessctl -d smc::kbd_backlight get)
              max=$(${pkgs.brightnessctl}/bin/brightnessctl -d smc::kbd_backlight max)
              echo $(( brightness * 100 / max )) > "$XDG_RUNTIME_DIR/wob.fifo"
            '';
          in
          ''
            -- Environment
            hl.env("XCURSOR_THEME", "Bibata-Modern-Ice")
            hl.env("XCURSOR_SIZE", "24")
            hl.env("HYPRCURSOR_THEME", "Bibata-Modern-Ice")
            hl.env("HYPRCURSOR_SIZE", "24")
            hl.env("ELECTRON_OZONE_PLATFORM_HINT", "wayland")
            hl.env("MOZ_ENABLE_WAYLAND", "1")
            hl.env("QT_QPA_PLATFORM", "wayland;xcb")
            hl.env("SDL_VIDEODRIVER", "wayland")
            hl.env("_JAVA_AWT_WM_NONREPARENTING", "1")
            ${lib.optionalString isGaming ''
            -- GPU pinning — Navi 22 is card1 on the dual-GPU gaming box.
            hl.env("AQ_DRM_DEVICES", "/dev/dri/card1")
            hl.env("DRI_PRIME", "pci-0000_03_00_0")
            ''}

            -- Startup
            hl.on("hyprland.start", function()
              -- Ensure hyprland-session.target starts even if HM's
              -- dbus-update-activation-environment chain fails upstream.
              hl.exec_cmd("systemctl --user start hyprland-session.target")
              hl.exec_cmd("mako")
              hl.exec_cmd("nm-applet --indicator")
              hl.exec_cmd("wl-paste --type text --watch cliphist store")
              hl.exec_cmd("wl-paste --type image --watch cliphist store")
              hl.exec_cmd("hyprctl setcursor Bibata-Modern-Ice 24")
              hl.exec_cmd("swayosd-server")
              ${lib.optionalString isMacbook ''hl.exec_cmd("hypridle")''}
            end)

            -- Animation curve and definitions
            hl.curve("snap", { type = "bezier", points = { {0.05, 0.9}, {0.1, 1.0} } })
            hl.animation({ leaf = "windows",    enabled = true, speed = 1, bezier = "snap" })
            hl.animation({ leaf = "windowsOut", enabled = true, speed = 1, bezier = "snap", style = "popin 80%" })
            hl.animation({ leaf = "layers",     enabled = true, speed = 1, bezier = "snap" })
            hl.animation({ leaf = "border",     enabled = true, speed = 2, bezier = "default" })
            hl.animation({ leaf = "fade",       enabled = true, speed = 1, bezier = "default" })
            hl.animation({ leaf = "workspaces", enabled = true, speed = 1, bezier = "snap" })

            -- Window rules
            -- Battle.net tray icon leaks as a tiny floating XWayland window.
            hl.window_rule({
              match = { class = "steam_app_0", title = "^$", float = true },
              workspace = "special silent",
            })

            -- Binds
            local mod = "SUPER"

            -- Apps
            hl.bind(mod .. " + T", hl.dsp.exec_cmd("ghostty"))
            hl.bind(mod .. " + E", hl.dsp.exec_cmd("nemo"))
            hl.bind(mod .. " + R", hl.dsp.exec_cmd("anyrun close || anyrun"))
            hl.bind(mod .. " + Q", hl.dsp.window.close())
            hl.bind(mod .. " + SHIFT + E", hl.dsp.exit())

            -- Floating / layout
            hl.bind(mod .. " + V", hl.dsp.window.float({ action = "toggle" }))
            hl.bind(mod .. " + F", hl.dsp.window.fullscreen())
            hl.bind(mod .. " + P", hl.dsp.window.pseudo())
            hl.bind(mod .. " + S", hl.dsp.layout("togglesplit"))

            -- Focus
            hl.bind(mod .. " + left",  hl.dsp.focus({ direction = "left" }))
            hl.bind(mod .. " + right", hl.dsp.focus({ direction = "right" }))
            hl.bind(mod .. " + up",    hl.dsp.focus({ direction = "up" }))
            hl.bind(mod .. " + down",  hl.dsp.focus({ direction = "down" }))
            hl.bind(mod .. " + H",     hl.dsp.focus({ direction = "left" }))
            hl.bind(mod .. " + K",     hl.dsp.focus({ direction = "up" }))
            hl.bind(mod .. " + J",     hl.dsp.focus({ direction = "down" }))

            -- Power menu — dismiss launcher if open, then show menu
            hl.bind(mod .. " + L", hl.dsp.exec_cmd("anyrun close 2>/dev/null; ${powerMenu}"))

            -- Move windows
            hl.bind(mod .. " + SHIFT + left",  hl.dsp.window.move({ direction = "left" }))
            hl.bind(mod .. " + SHIFT + right", hl.dsp.window.move({ direction = "right" }))
            hl.bind(mod .. " + SHIFT + up",    hl.dsp.window.move({ direction = "up" }))
            hl.bind(mod .. " + SHIFT + down",  hl.dsp.window.move({ direction = "down" }))

            -- Workspaces
            hl.bind(mod .. " + 1", hl.dsp.focus({ workspace = 1 }))
            hl.bind(mod .. " + 2", hl.dsp.focus({ workspace = 2 }))
            hl.bind(mod .. " + 3", hl.dsp.focus({ workspace = 3 }))
            hl.bind(mod .. " + 4", hl.dsp.focus({ workspace = 4 }))
            hl.bind(mod .. " + 5", hl.dsp.focus({ workspace = 5 }))
            hl.bind(mod .. " + 6", hl.dsp.focus({ workspace = 6 }))
            hl.bind(mod .. " + 7", hl.dsp.focus({ workspace = 7 }))
            hl.bind(mod .. " + 8", hl.dsp.focus({ workspace = 8 }))
            hl.bind(mod .. " + 9", hl.dsp.focus({ workspace = 9 }))
            hl.bind(mod .. " + 0", hl.dsp.focus({ workspace = 10 }))

            hl.bind(mod .. " + SHIFT + 1", hl.dsp.window.move({ workspace = 1,  follow = false }))
            hl.bind(mod .. " + SHIFT + 2", hl.dsp.window.move({ workspace = 2,  follow = false }))
            hl.bind(mod .. " + SHIFT + 3", hl.dsp.window.move({ workspace = 3,  follow = false }))
            hl.bind(mod .. " + SHIFT + 4", hl.dsp.window.move({ workspace = 4,  follow = false }))
            hl.bind(mod .. " + SHIFT + 5", hl.dsp.window.move({ workspace = 5,  follow = false }))
            hl.bind(mod .. " + SHIFT + 6", hl.dsp.window.move({ workspace = 6,  follow = false }))
            hl.bind(mod .. " + SHIFT + 7", hl.dsp.window.move({ workspace = 7,  follow = false }))
            hl.bind(mod .. " + SHIFT + 8", hl.dsp.window.move({ workspace = 8,  follow = false }))
            hl.bind(mod .. " + SHIFT + 9", hl.dsp.window.move({ workspace = 9,  follow = false }))
            hl.bind(mod .. " + SHIFT + 0", hl.dsp.window.move({ workspace = 10, follow = false }))

            -- Screenshots — Shift+Super+S matches GNOME binding
            hl.bind(mod .. " + SHIFT + S", hl.dsp.exec_cmd("hyprshot -m region --clipboard-only"))
            hl.bind("Print",               hl.dsp.exec_cmd("hyprshot -m output --clipboard-only"))

            -- Settings shortcut — Super+I matches GNOME binding
            hl.bind(mod .. " + I", hl.dsp.exec_cmd("pavucontrol"))

            -- Custom shortcuts
            hl.bind(mod .. " + Z", hl.dsp.exec_cmd("zen-beta"))

            -- Mouse window manipulation
            hl.bind(mod .. " + mouse:272", hl.dsp.window.drag(),   { mouse = true })
            hl.bind(mod .. " + mouse:273", hl.dsp.window.resize(), { mouse = true })

            -- Volume / brightness (repeating)
            hl.bind("XF86AudioRaiseVolume",  hl.dsp.exec_cmd("swayosd-client --output-volume raise"),       { repeating = true })
            hl.bind("XF86AudioLowerVolume",  hl.dsp.exec_cmd("swayosd-client --output-volume lower"),       { repeating = true })
            hl.bind("XF86AudioMute",         hl.dsp.exec_cmd("swayosd-client --output-volume mute-toggle"), { repeating = true })
            hl.bind("XF86MonBrightnessUp",   hl.dsp.exec_cmd("swayosd-client --brightness raise"),          { repeating = true })
            hl.bind("XF86MonBrightnessDown", hl.dsp.exec_cmd("swayosd-client --brightness lower"),          { repeating = true })
            ${lib.optionalString isMacbook ''
            hl.bind("XF86KbdBrightnessUp",   hl.dsp.exec_cmd("${kbdBrightUp}"),   { repeating = true })
            hl.bind("XF86KbdBrightnessDown", hl.dsp.exec_cmd("${kbdBrightDown}"), { repeating = true })
            ''}

            -- Media keys (locked — work through lockscreen)
            hl.bind("XF86AudioPlay", hl.dsp.exec_cmd("playerctl play-pause"), { locked = true })
            hl.bind("XF86AudioNext", hl.dsp.exec_cmd("playerctl next"),        { locked = true })
            hl.bind("XF86AudioPrev", hl.dsp.exec_cmd("playerctl previous"),    { locked = true })
          '';
      };

      programs.anyrun = {
        enable = true;
        config = {
          plugins = [ anyrun-pkgs.applications ];
          x.fraction = 0.5;
          y.fraction = 0.25;
          width.absolute = 350;
          height.absolute = 0;
          hideIcons = false;
          ignoreExclusiveZones = false;
          layer = "overlay";
          hidePluginInfo = true;
          closeOnClick = true;
          maxEntries = 8;
        };
        extraCss =
          let c = config.lib.stylix.colors; in
          ''
            * { all: unset; font-family: "FiraMono Nerd Font", monospace; font-size: 13px; }
            window { background: transparent; }
            box.main {
              background: #${c.base00};
              border: 1px solid #${c.base03};
              border-radius: 10px;
              padding: 8px;
              margin: 16px;
            }
            text {
              background: #${c.base01};
              color: #${c.base05};
              caret-color: #${c.base0D};
              padding: 8px 16px;
              border-radius: 6px;
              min-height: 0;
            }
            list.plugin { background: transparent; }
            .matches    { background: transparent; }
            .match {
              padding: 4px 16px;
              border-radius: 6px;
              color: #${c.base05};
              background: transparent;
            }
            .match:selected {
              background: #${c.base02};
              border: none;
            }
            label.match.description { color: #${c.base04}; font-size: 11px; }
          '';
        extraConfigFiles."applications.ron".text = ''
          Config(
            desktop_actions: false,
            max_entries: 8,
            terminal: Some("ghostty"),
          )
        '';
      };

      programs.hyprlock.enable = true;

      services.hypridle = lib.mkIf isMacbook {
        enable = true;
        settings = {
          general = {
            lock_cmd         = "pidof hyprlock || hyprlock";
            before_sleep_cmd = "loginctl lock-session";
            after_sleep_cmd  = "hyprctl dispatch dpms on";
          };
          listener = [
            {
              timeout    = 300;   # 5 min — lock
              on-timeout = "loginctl lock-session";
            }
            {
              timeout    = 420;   # 7 min — display off
              on-timeout = "hyprctl dispatch dpms off";
              on-resume  = "hyprctl dispatch dpms on";
            }
            {
              timeout    = 600;   # 10 min — suspend
              on-timeout = "systemctl suspend";
            }
          ];
        };
      };

      # Scope all HM Wayland services (hyprpaper, waybar, …) to the
      # Hyprland session so they don't crash-loop in a GNOME session.
      wayland.systemd.target = "hyprland-session.target";

      programs.waybar = {
        enable = true;
        systemd.enable = true;

        settings.mainBar = {
          layer = "top";
          position = "top";
          height = 30;
          spacing = 6;

          modules-left   = [ "hyprland/workspaces" ];
          modules-center = [ "clock" ];
          modules-right  = lib.optionals isMacbook [ "battery" ] ++ [ "group/tray-drawer" ];

          "hyprland/workspaces" = {
            format = "{name}";
            on-click = "activate";
            sort-by-number = true;
          };

          clock = {
            format = "{:%H:%M}";
            tooltip-format = "<big>{:%A, %d %B %Y}</big>\n<tt><small>{calendar}</small></tt>";
          };

          "group/tray-drawer" = {
            orientation = "horizontal";
            drawer = {
              transition-duration = 500;
              transition-left-to-right = false;
            };
            modules = [ "custom/tray-handle" "pulseaudio" "tray" ];
          };

          "custom/tray-handle" = {
            format = builtins.fromJSON ''"\ue0b2"''; # U+E0B2 Nerd Font powerline filled left-arrow
            tooltip = false;
          };

          # Pulseaudio module, now conditionally visible
          pulseaudio = {
            format = "{icon} {volume}%";
            format-muted = "  muted";
            format-icons = {
              default = [ "" "" "" ];
              headphone = "";
              headset = "";
            };
            on-click = "pavucontrol";
            scroll-step = 5;
          };

          # Tray module, now conditionally visible
          tray = {
            icon-size = 16;
            spacing = 8;
          };
        } // lib.optionalAttrs isMacbook {
          battery = {
            format = "{capacity}% {icon}";
            format-charging = "{capacity}% ";
            format-icons = [ "" "" "" "" "" ];
            states = { warning = 30; critical = 15; };
          };
        };

        style = ''
          * {
            font-family: "FiraMono Nerd Font", monospace;
            font-size: 13px;
            min-height: 0;
            border: none;
            border-radius: 0;
          }

          window#waybar {
            background: alpha(@base00, 0.82);
            color: @base05;
          }

          #workspaces {
            margin-left: 6px;
          }

          #workspaces button {
            padding: 0 8px;
            color: @base03;
            background: transparent;
          }

          #workspaces button.active {
            color: @base05;
          }

          #workspaces button:hover {
            background: alpha(@base05, 0.08);
            color: @base05;
            box-shadow: none;
            text-shadow: none;
          }

          #clock {
            color: @base05;
            font-weight: 500;
          }

          #pulseaudio,
          #tray {
            padding: 0 10px;
            color: @base05;
          }

          #pulseaudio.muted {
            color: @base03;
          }

          #tray {
            margin-right: 6px;
          }

          #custom-tray-handle {
            padding: 0 0px;
            color: @base05;
          }

          #battery {
            padding: 0 10px;
            color: @base05;
          }
          #battery.warning { color: @base0A; }
          #battery.critical { color: @base08; }
        '';
      };

    };
  };
}
