{ config, pkgs, lib, ... }: 
let
  # Add nixpkgs-unstable channel with the following command:
  # nix-channel --add https://nixos.org/channels/nixpkgs-unstable nixpkgs-unstable && nix-channel --update
  unstable = import <nixpkgs-unstable> { config = config.nixpkgs.config; };
  host_name = "incineroar";
  host_fqdn = "${host_name}.brenise.dev";
in
{
  imports = [
    ./hardware-configuration.nix
  ];
  nix.settings.experimental-features = [ "nix-command" "flakes" ];
  nixpkgs.config.allowUnfreePredicate = pkg:
    builtins.elem (lib.getName pkg) [
      "nvidia-x11"
      "nvidia-settings"
      "nvidia-persistenced"
      "steam"
      "steam-original"
      "steam-unwrapped"
      "steam-run"
    ];
  hardware = {
    graphics.enable = true;
    nvidia = { # RTX 2080 Ti
      open = true;
    # package = config.boot.kernelPackages.nvidiaPackages.beta;
    # modesetting.enable = true; # needed for Wayland compositors, might fix screen tearing
    };
  };

  boot = {
    kernelPackages = pkgs.linuxPackages_latest;
    loader = {
      systemd-boot.enable = true;
      efi.canTouchEfiVariables = true;
    };
  };

  hardware.bluetooth.enable = true;

  networking = {
    hostName = "${host_name}";
    firewall.enable = false;
    interfaces = {
      enp3s0.ipv4.addresses = [{
        address = "192.168.1.36";
        prefixLength = 24;
      }];
    };
    defaultGateway = {
      address = "192.168.1.1";
      interface = "enp3s0";
    };
    # TODO https://nixos.wiki/wiki/Encrypted_DNS
    nameservers = [ "1.1.1.1" "8.8.8.8" ];
  };

  time.timeZone = "America/Los_Angeles";

  i18n.defaultLocale = "en_US.UTF-8";
  console = {
    font = "Lat2-Terminus16";
#   keyMap = "us";
    useXkbConfig = true; # use xkbOptions in tty.
  };

  users = {
    users = {

      root = {
        openssh.authorizedKeys.keyFiles = [
          /etc/nixos/ssh/authorized_keys
        ];
      };

      blee = {
        openssh.authorizedKeys.keyFiles = [
          /etc/nixos/ssh/authorized_keys
        ];
        isNormalUser = true;
        extraGroups = [ "wheel" ];
        packages = with pkgs; [
          gnumake
          chromium
          firefox
          ffmpeg
          obs-studio
          kate # kwrite
          glances
          libsForQt5.kcalc
          # slack # sso auth very broken
          synergy

          # Build vim huge with clipboard support
          (vim_configurable.overrideAttrs (oldAttrs: {
            features = "huge";
          }))
          python311
          python311Packages.pip
          python311Packages.ipython
          python311Packages.huggingface-hub
          curl
          dnsutils
          git
          git-lfs
          jq
          imagemagick
          pass
          netcat
          mediainfo
          tmux
          vlc
          wget
        ];
      };

#     steam = {
#       openssh.authorizedKeys.keyFiles = [
#         /etc/nixos/ssh/authorized_keys
#       ];
#       isNormalUser = true;
#       extraGroups = [ "wheel" ];
#     };

      timburr = {
        openssh.authorizedKeys.keyFiles = [
          /etc/nixos/ssh/authorized_timburr_keys
        ];
        isNormalUser = true;
        extraGroups = [ "wheel" ];
      };
    };
  };

  environment = {
    systemPackages = with pkgs; [
      cryptsetup
      doas
      dig
      file
      fzf
      htop
      libressl
      nettools
      parted
      psmisc
      rsync
      screen
      tcpdump
      tree
      vim
      wireguard-tools
      whois
      # GPU tools
      inxi
      glxinfo
      pciutils # lspci
      vulkan-tools
    ];

    shellInit = ''
      pheonix() {
          systemctl restart "$1"
          journalctl -fu "$1"
      }
    '';

    plasma5.excludePackages = with pkgs.libsForQt5; [
      #elisa # music player
      #gwenview # image viewer
      #okular # document viewer
      #oxygen # widgets
      #khelpcenter
      #konsole
      plasma-browser-integration
      #print-manager
    ];
  };

  programs = {
    fish.enable = true;
    tmux = {
      enable = true;
      extraConfig = ''
        set-option -g default-shell ${pkgs.fish}/bin/fish
      ''; # This doesn't seem to work
    };
    vim = {
      enable = true;
      defaultEditor = true;
    };
    bash = {
      shellAliases = {
        ll = "ls -lAF --classify --group-directories-first";
        l  = "ls -lF --classify --group-directories-first";
      };
      # https://nixos.wiki/wiki/Fish
      interactiveShellInit = ''
        if [[ $(${pkgs.procps}/bin/ps --no-header --pid=$PPID --format=comm) != "fish" && -z ''${BASH_EXECUTION_STRING} ]]
        then
          shopt -q login_shell && LOGIN_OPTION='--login' || LOGIN_OPTION=""
          exec ${pkgs.fish}/bin/fish $LOGIN_OPTION
        fi
      '';
    };
    mtr.enable = true;
    gnupg.agent = {
      enable = true;
      enableSSHSupport = true;
    };
    steam.enable = true;
    chromium = {
      enable = true;
      extraOpts = {
        "SpellcheckEnabled" = false;
      };
    };
  };

  security = {
    sudo.enable = false;
    doas = {
      enable = true;
      extraRules = [
        {
          users = [ "blee" ];
          persist = true;
        }
        {
          users = [ "timburr" ];
          noPass = true;
          cmd = "reboot";
        }
        {
          users = [ "timburr" ];
          noPass = true;
          cmd = "halt";
        }
      ];
    };
  };

  services = {

    openssh.enable = true;

    # https://discourse.nixos.org/t/bluetooth-a2dp-sink-not-showing-up-in-pulseaudio-on-nixos/32447/4?u=bleetube
    pipewire = {
      enable = true;
      pulse.enable = true;
    };

    syncthing = {
        enable = true;
        user = "blee";
        dataDir = "/home/blee/Documents";
    };
    journald.extraConfig = "MaxRetentionSec=30day";

    # https://github.com/NixOS/nixpkgs/blob/nixos-23.05/nixos/modules/services/monitoring/prometheus/exporters.nix
    prometheus.exporters.node = {
      enable = true;
      port = 8030;
#     openFirewall = true;
      enabledCollectors = [
        "cpu.info"
        "interrupts"
        "netstat"
        "vmstat"
        "systemd"
        "tcpstat"
        "processes"
      ];
    };

    caddy = {
      enable = true;
      logFormat = "output discard";
      extraConfig = let
        tlsConfig = ''
          tls {
            dns namecheap {
              api_key {env.NAMECHEAP_API_KEY}
              user {env.NAMECHEAP_API_USER}
              api_endpoint https://api.namecheap.com/xml.response
            }
          }
        '';
      in ''
        ${host_fqdn}:4430 { # node_exporter
          ${tlsConfig}
          reverse_proxy http://127.0.0.1:8030
        }

        ${host_fqdn} { # open-webui
          ${tlsConfig}
          reverse_proxy http://127.0.0.1:8080

        }
        ${host_fqdn}:4431 { # litellm
          ${tlsConfig}
          reverse_proxy http://127.0.0.1:8031
        }
        ${host_fqdn}:4434 { # ollama
          ${tlsConfig}
          reverse_proxy http://127.0.0.1:11434
        }

        ${host_fqdn}:4432 { # comfyui
          ${tlsConfig}
          reverse_proxy http://127.0.0.1:8081

          handle /output/* {
            root /opt/comfyui
            file_server browse
          }
          handle /meeseeks/* {
            root /mnt/meow/squirtle/var/ftp
            file_server browse
          }

        }

        ${host_fqdn}:4440 { # sunshine
          ${tlsConfig}
          reverse_proxy http://127.0.0.1:47990
        }

      '';
    };

    sunshine.enable = true;
#   sunshine.capSysAdmin = true;
    displayManager = {
      sddm.enable = true;
      #defaultSession = "plasmawayland";
      autoLogin = {
        enable = true;
        user = "blee";
      };
    };
    xserver = {
      enable = true;
      videoDrivers = ["nvidia"]; # nvidia-smi, kernel-modules
      desktopManager.plasma5.enable = true;
    };
  # ollama = {
  #   enable = true;
  #   package = unstable.ollama; # outdated
  # # port = 8034; # not in stable yet
  # };
  };

  systemd = {
    services = {

      # BUG: unable to attach to the tmux session. LLMs can't figure out why 1/9/2025
#     playground = {
#       wantedBy = [ "multi-user.target" ];
#       after = [ "network.target" ];
#       serviceConfig = {
#         Type = "forking";
#         User = "blee";
#         WorkingDirectory = "/opt/playground";
#         Environment = "NIX_PATH=nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos:nixos-config=/etc/nixos/configuration.nix:/nix/var/nix/profiles/per-user/root/channels";
#       };
#       script = "${pkgs.nix}/bin/nix-shell";
#     };

      ollama = {
        wantedBy = [ "multi-user.target" ];
        after = [ "network.target" ];
        serviceConfig = {
          Type = "forking";
          User = "blee";
          WorkingDirectory = "/opt/ollama";
          Environment = "NIX_PATH=nixpkgs=/nix/var/nix/profiles/per-user/root/channels/nixos:nixos-config=/etc/nixos/configuration.nix:/nix/var/nix/profiles/per-user/root/channels";
        };
        script = "${pkgs.nix}/bin/nix-shell";
      };

      caddy = {
        serviceConfig = {
          EnvironmentFile = "/var/src/secrets/namecheap";
          ExecStart = [
            ""  # This empty string clears the existing ExecStart commands
            "/opt/bin/caddy run --config /etc/caddy/caddy_config --adapter caddyfile"
          ];
          ExecReload = [
            ""  # This empty string clears the existing ExecReload commands
            "/opt/bin/caddy reload --config /etc/caddy/caddy_config --adapter caddyfile --force"
          ];

        };
      };

      "sleep-at-night" = {
        script = ''
          ${pkgs.utillinux}/bin/rtcwake -m no -l -t "$(date +\%s -d 'tomorrow 10:00')"
          ${pkgs.systemd}/bin/systemctl suspend
        '';
        serviceConfig = {
          Type = "oneshot";
        };
      };
    }; # services


    timers."sleep-at-night" = {
      wantedBy = [ "timers.target" ];
      timerConfig = {
        OnCalendar = "*-*-* 20:00:00";
      # Persistent = true;
      };
    };
  };

  system.stateVersion = "24.11";
}