{ inputs, lib, config, pkgs, ...}:
let 
  unstable = import inputs.nixpkgs-unstable { system = "x86_64-linux"; config.allowUnfree = true; };
  isOnTheGo = builtins.elem "on-the-go" config.system.nixos.tags;
in
{
  options.hypr = {
    enable = lib.mkEnableOption "Enable hyprland window manager.";
    systemPackages = lib.mkOption {
      default = [];
      description = "Add any additional packages desired. Merged with sway defaults.";
    };
    user = lib.mkOption {
      type = lib.types.str;
    };
  };

  config = lib.mkIf config.hypr.enable {

    catppuccin.enable = true;
    catppuccin.flavor = "macchiato";
    catppuccin.accent = "lavender";
    programs.hyprland.enable = true;
    # programs.hyprland.package = unstable.hyprland;
    # programs.hyprland.portalPackage = pkgs.xdg-desktop-portal-hyprland;
    # programs.steam.enable = true;
    # For electron apps in wayland

    environment.systemPackages = with pkgs; lib.lists.flatten [
      [
        bash
        egl-wayland
        foot
        unstable.ghostty
        git
        glib # gsettings
        man-pages
        man-pages-posix
        nbfc-linux
        nautilus
        # swww
        xdg-utils
        zsh
        lxqt.lxqt-policykit
      ]
      config.hypr.systemPackages
    ];
    environment = {
      variables = {
        # If cursor is not visible, try to set this to "on".
        XDG_CURRENT_DESKTOP = "Hyprland";
        XDG_SESSION_TYPE = "wayland";
        XDG_SESSION_DESKTOP = "Hyprland";
      };
      sessionVariables = {
        # use wayland
        MOZ_ENABLE_WAYLAND = "1";
        # NIXOS_OZONE_WL = "1";
        T_QPA_PLATFORM = "wayland";
        GDK_BACKEND = "wayland";
        WLR_NO_HARDWARE_CURSORS = "1";
        # For hyprland
        # Only enable if not using on-the-go
        GBM_BACKEND = if isOnTheGo then "" else "nvidia-drm";
        __GLX_VENDOR_LIBRARY_NAME = if isOnTheGo then "" else "nvidia";
      };
    };
    xdg.portal = {
        enable = true;
        xdgOpenUsePortal = true;
        config = {
          common.default = [ "gtk" ];
          hyprland.default = [ "hyprland" "gtk" ];
        };
        extraPortals = with pkgs; [
            xdg-desktop-portal-hyprland
            xdg-desktop-portal-gtk
            xdg-desktop-portal-wlr
        ];
    };

    virtualisation = {
        docker = {
          enable = true;
          enableOnBoot = true;
          package = unstable.docker_25;
        };
        # containers.cdi.dynamic.nvidia.enable = true;
        # podman = {
        #     enable = true;
        #     dockerCompat = true;
        # };
    };
    # enable nvidia passthru for containers
    # hardware.nvidia-container-toolkit.enable = true;

    # programs.thunar = {
    #     enable = true;
    #     plugins = with pkgs.xfce; [
    #         thunar-archive-plugin
    #         thunar-volman
    #     ];
    # };
    # programs.file-roller.enable = true;
    # For nautilus
    services.gnome.sushi.enable = true;
    programs.nautilus-open-any-terminal = {
      enable = true;
      terminal = "ghostty";
    };
    programs.xfconf.enable = true;
    programs.regreet.enable = true;
    programs.zsh.enable = true;
    programs.ssh.startAgent = true;

    services.printing = {
      enable = true;
      browsing = true;
      drivers = [ pkgs.brlaser ];
    };

    services.avahi = {
      enable = true;
      nssmdns4 = true;
      openFirewall = true;
    };

    services.fprintd.enable = true;
    services.greetd = {
      enable = true;
      settings = rec {
        initial_session = {
          command = "${unstable.hyprland}/bin/Hyprland";
          user = config.hypr.user;
        };
        default_session = initial_session;
      };
    };
    # disable lid switch sleep when plugged into power, laptop docked
    services.logind.lidSwitchExternalPower = "ignore";
    # For yubioath desktop
    services.pcscd.enable = true;
    security.polkit.enable = true;
    # Keyring setup
    # security.pam.services.gdm.enableGnomeKeyring = true;
    security.pam.services.greetd.enableGnomeKeyring = true;
    security.pam.services.login.enableGnomeKeyring = true;
    services.gnome.gnome-keyring.enable = true;
    # Audio
    security.rtkit.enable = true;
    services.pipewire = {
      enable = true;
      audio.enable = true;
      alsa.enable = true;
      alsa.support32Bit = true;
      pulse.enable = true;
      wireplumber.enable = true;
      wireplumber.extraConfig = {
        "wireplumber.settings" = {
          bluetooth.autoswitch-to-headset-profile = false;
        };
        bluetoothEnhancements = {
          "monitor.bluez.properties" = {
              "bluez5.enable-sbc-xq" = true;
              "bluez5.enable-msbc" = true;
              "bluez5.enable-hw-volume" = true;
              # Default roles: https://pipewire.pages.freedesktop.org/wireplumber/daemon/configuration/bluetooth.html#monitor-properties
              "bluez5.roles" = [ "a2dp_sink" "a2dp_source" "bap_sink" "bap_source" "hfp_hf" "hfp_ag" ];
          };
        };
      };
    };
    services.blueman.enable = true;
    services.flatpak.enable = true;
    services.gvfs.enable = true;  # file manager mount, trash, etc
    services.tumbler.enable = true; # thunar thumbnails
    services.openssh.enable = true;
    services.dbus.enable = true;

    services.syncthing = {
      enable = true;
      dataDir = "/home/${config.hypr.user}/.syncthing";
      openDefaultPorts = true;
      user = config.hypr.user;
    };
    systemd.services.syncthing.environment.STNODEFAULTFOLDER = "true"; # Don't create default ~/Sync folder

    services.usbmuxd.enable = true;
    hardware.bluetooth = {
      enable = true;
      powerOnBoot = true; # powers up the default Bluetooth controller on boot
      settings  = {
        General = {
          Name = "Nate-Vasion";
          ControlleMode = "dual";
          FastConnectable = "true";
          Experimental = "true";
        };
        Policy = { AutoEnable = "true"; };
        LE = { EnableAdvMonInterleaveScan = "true"; };
      };
    };
    #
    # Nvidia Setup
    #

    # Use latest kernel
    # boot.kernelPackages = unstable.linuxPackages_latest;
    
    services.xserver.videoDrivers = [ "nvidia" ];
    hardware = {
      graphics = {
        enable = true;
        # package = unstable.mesa.drivers;
        enable32Bit = true;
        # package32 = unstable.pkgsi686Linux.mesa.drivers;
      };
      nvidia = {
        # Modesetting is required.
        modesetting.enable = true;
        # Nvidia power management. Experimental, and can cause sleep/suspend to fail.
        # Enable this if you have graphical corruption issues or application crashes after waking
        # up from sleep. This fixes it by saving the entire VRAM memory to /tmp/ instead 
        # of just the bare essentials.
        powerManagement.enable = true;

        # Fine-grained power management. Turns off GPU when not in use.
        # Experimental and only works on modern Nvidia GPUs (Turing or newer).
        powerManagement.finegrained = true;

        # Use the NVidia open source kernel module (not to be confused with the
        # independent third-party "nouveau" open source driver).
        # Support is limited to the Turing and later architectures. Full list of 
        # supported GPUs is at: 
        # https://github.com/NVIDIA/open-gpu-kernel-modules#compatible-gpus 
        # Only available from driver 515.43.04+
        # Currently alpha-quality/buggy, so false is currently the recommended setting.
        open = false;

        # Enable the Nvidia settings menu,
  	    # accessible via `nvidia-settings`.
        nvidiaSettings = true;

        # Optionally, you may need to select the appropriate driver version for your specific GPU.
        package = config.boot.kernelPackages.nvidiaPackages.stable;
        prime = {
          # sync.enable = true;
          offload.enable = true;
          offload.enableOffloadCmd = true; # adds `nvidia-offload` command to env
          intelBusId =  "PCI:0:2:0";
          nvidiaBusId = "PCI:1:0:0";
        };
      };
    };
    # Create special on the go boot entry
    specialisation = {
      on-the-go.configuration = {
        system.nixos.tags = [ "on-the-go" ];

        boot.extraModprobeConfig = ''
          blacklist nouveau
          options nouveau modeset=0
        '';
  
        services.udev.extraRules = ''
          # Remove NVIDIA USB xHCI Host Controller devices, if present
          ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c0330", ATTR{power/control}="auto", ATTR{remove}="1"
          # Remove NVIDIA USB Type-C UCSI devices, if present
          ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x0c8000", ATTR{power/control}="auto", ATTR{remove}="1"
          # Remove NVIDIA Audio devices, if present
          ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x040300", ATTR{power/control}="auto", ATTR{remove}="1"
          # Remove NVIDIA VGA/3D controller devices
          ACTION=="add", SUBSYSTEM=="pci", ATTR{vendor}=="0x10de", ATTR{class}=="0x03[0-9]*", ATTR{power/control}="auto", ATTR{remove}="1"
        '';
        hardware.nvidia = {
          prime.offload.enable = lib.mkForce false;
          prime.offload.enableOffloadCmd = lib.mkForce false;
          powerManagement.finegrained = lib.mkForce false;
          prime.sync.enable = lib.mkForce false;
        };
        boot.blacklistedKernelModules = [ "nouveau" "nvidia" "nvidia_drm" "nvidia_modeset" ];
        # Hint to kernel for integrated graphics, ID from command `$ nix-shell -p pciutils --run "lspci -nn | grep VGA"`
        boot.kernelParams = [ "i915.force_probe=a7a0" "acpi_backlight=native" ];
        # Default drivers
        services.xserver.videoDrivers = [ "modesetting" "fbdev" ];
      };
    };
    nixpkgs.config.allowUnfree = true;
  };
}