{ config, inputs, outputs, pkgs, ... }: {
  boot = {
    initrd.kernelModules = [ "zfs" ];
    kernel.sysctl = {
      "net.ipv4.ip_forward" = 1;
      "net.ipv4.conf.all.proxy_arp" = 1;
    };
    #kernelPackages = pkgs.linuxPackages_6_10;
    loader = {
      efi = {
        canTouchEfiVariables = true;
        efiSysMountPoint = "/efiboot/efi1";
      };
      systemd-boot = {
        enable = true;
        extraInstallCommands = ''
          ${pkgs.rsync}/bin/rsync -av --delete /efiboot/efi1/ /efiboot/efi2
        '';
      };
      timeout = 3;
    };
    supportedFilesystems = [ "zfs" ];
  };

  environment.etc."nftables-vpn.conf".text = ''
    # VPN firewall
    
    flush ruleset
    
    table inet filter {
    	chain input {
    		type filter hook input priority filter; policy drop;
    
    		# established/related connections
    		ct state established,related accept
    
    		# invalid connections
    		ct state invalid drop
    
    		# loopback interface
    		iif lo accept
    
    		# ICMP (routers may also want: mld-listener-query, nd-router-solicit)
    		#ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, echo-reply, echo-request, nd-neighbor-advert, nd-neighbor-solicit, nd-router-advert, packet-too-big, parameter-problem, time-exceeded } accept
    		ip protocol icmp icmp type { destination-unreachable, echo-reply, echo-request, parameter-problem, router-advertisement, source-quench, time-exceeded } accept
    
    		# services
    		iif veth.vpn tcp dport 8080 accept # qBittorrent
    		iif veth.vpn tcp dport 9696 accept # Prowlarr
    		iifname wg1 tcp dport { 49152-65535 } accept # Transmission
    	}
    
    	chain output {
    		type filter hook output priority filter; policy drop;
    
    		# explicitly allow my DNS traffic without VPN
    		skuid nipsy ip daddr 192.168.1.1 tcp dport domain accept
    		skuid nipsy ip daddr 192.168.1.1 udp dport domain accept
    
    		# explicitly allow my traffic without VPN
    		oifname veth.vpn skuid nipsy tcp sport 8080 accept # qBittorrent
    		oifname veth.vpn skuid nipsy tcp sport 9696 accept # Prowlarr
    		oifname veth.vpn skuid nipsy ip daddr 192.168.1.2 tcp dport { 7878, 8686, 8787, 8989 } accept # Prowlarr to { Radarr, Lidarr, Readarr, Sonarr }
    
    		# allow any traffic out through VPN
    		oifname wg1 accept
    
    		# drop everything else
    		counter drop
    	}
    
    	chain forward {
    		type filter hook forward priority filter; policy drop;
    	}
    }
  '';

  environment.systemPackages = with pkgs; [
    angband
    assaultcube
    bsdgames
    bzflag
    extremetuxracer
    frozen-bubble
    hedgewars
    kobodeluxe
    lidarr
    mailutils
    megacmd
    moc
    nethack
    openttd
    prowlarr
    qbittorrent-nox
    radarr
    rdiff-backup
    readarr
    scorched3d
    signal-desktop
    sonarr
    superTux
    superTuxKart
    umoria
    warzone2100
    wpa_supplicant
    xonotic-sdl
    xpilot-ng
  ];

  imports = [
    ./disks.nix
    ./hardware-configuration.nix
    ./services.nix
    ../common/core
    ../common/optional/adb.nix
    ../common/optional/db.nix
    ../common/optional/dev.nix
    ../common/optional/ebooks.nix
    ../common/optional/games.nix
    ../common/optional/google-authenticator.nix
    ../common/optional/misc.nix
    ../common/optional/multimedia.nix
    ../common/optional/pipewire.nix
    ../common/optional/sdr.nix
    ../common/optional/services/chrony.nix
    ../common/optional/services/openssh.nix
    ../common/optional/services/xorg.nix
    ../common/optional/sound.nix
    ../common/optional/zfs.nix
    ../common/users/nipsy
    ../common/users/root
  ];

  networking = {
    defaultGateway = {
      address = "192.168.1.1";
      interface = "wlp5s0";
    };
    domain = "bitgnome.net";
    hostId = "2ae4c89f";
    hostName = "arrakis";
    interfaces = {
      wlp5s0 = {
        ipv4.addresses = [
          { address = "192.168.1.2"; prefixLength = 24; }
        ];
      };
    };
    nameservers = [ "192.168.1.1" ];
    nftables.enable = true;
    useDHCP = false;
    wg-quick.interfaces = {
      wg0 = {
        address = [
          "10.4.20.1/24"
        ];
        listenPort = 51820;
        peers = [
          { # black-sheep
            allowedIPs = [ "10.4.20.2/32" ];
            presharedKeyFile = "${config.sops.secrets."wireguard/black-sheep_psk".path}";
            publicKey = "wQsGWsfXI2+GmKHdCH2V2xIeTyV2YlH/IFp6gerxcW8=";
          }
          { # lilnasx
            allowedIPs = [ "10.4.20.3/32" ];
            presharedKeyFile = "${config.sops.secrets."wireguard/lilnasx_psk".path}";
            publicKey = "87cANtuPf28vGrB0uL69/tXgsD/30FUYt/XevQjpz3o=";
          }
          { # ramped
            allowedIPs = [ "10.4.20.4/32" ];
            presharedKeyFile = "${config.sops.secrets."wireguard/ramped_psk".path}";
            publicKey = "TvE3f0QKJXUn8pxmKMaztFvRIdi9z9dxNDN2KNdtRXQ=";
          }
          { # homer
            allowedIPs = [ "10.4.20.5/32" ];
            presharedKeyFile = "${config.sops.secrets."wireguard/homer_psk".path}";
            publicKey = "FBc2ZnypwHgjLQcZrwzPR35gax8JsXLa1ZcZy6iAc3Q=";
          }
          { # treebeard
            allowedIPs = [ "10.4.20.6/32" ];
            presharedKeyFile = "${config.sops.secrets."wireguard/treebeard_psk".path}";
            publicKey = "aYh7q1QNmz6TLYx5OsZcyHQe45Dv0SyIOCtRp1NHDU8=";
          }
          { # lolli
            allowedIPs = [ "10.4.20.7/32" ];
            presharedKeyFile = "${config.sops.secrets."wireguard/lolli_psk".path}";
            publicKey = "npt86Lt/f/9J3qS6u6C0X1MFHIONaA5PKE6lzwwUxTc=";
          }
          { # timetrad
            allowedIPs = [ "10.4.20.8/32" ];
            presharedKeyFile = "${config.sops.secrets."wireguard/timetrad_psk".path}";
            publicKey = "/lWCEMGRIr3Gl/3GQYuweAKylhH5H2KqamiXeocYFVM=";
          }
          { # ginaz
            allowedIPs = [ "10.4.20.254/32" ];
            presharedKeyFile = "${config.sops.secrets."wireguard/ginaz_psk".path}";
            publicKey = "GuE9PVeS0IDTcaBxOSJmKlvEx2xflxwVGOU+uM0HhBk=";
          }
        ];
        privateKeyFile = "${config.sops.secrets."wireguard/arrakis_key".path}";
      };
    };
    wireless = {
      enable = true;
      networks = {
        "Crystal Palace" = {
          pskRaw = "ext:psk_crystal_palace";
        };
      };
      secretsFile = "${config.sops.secrets."wpa_supplicant".path}";
    };
  };

  nixpkgs = {
    config = {
      allowUnfree = true;
      permittedInsecurePackages = [
        "aspnetcore-runtime-6.0.36"
        "aspnetcore-runtime-wrapped-6.0.36"
        "dotnet-sdk-6.0.428"
        "dotnet-sdk-wrapped-6.0.428"
      ];
    };
    hostPlatform = "x86_64-linux";
    overlays = [
      #inputs.nvidia-patch.overlays.default
      outputs.overlays.additions
      outputs.overlays.modifications
      outputs.overlays.master-packages
      outputs.overlays.stable-packages
    ];
  };

  services.openssh.settings.X11Forwarding = true;
  services.xserver.videoDrivers = [ "nvidia" ];

  sops = {
    age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
    defaultSopsFile = ../secrets/arrakis.yaml;

    secrets = {
      "nftables/ssh" = {};
      "nix-access-token-github" = {};
      "wireguard/arrakis_key" = {};
      "wireguard/black-sheep_psk" = {};
      "wireguard/ginaz_psk" = {};
      "wireguard/homer_psk" = {};
      "wireguard/lilnasx_psk" = {};
      "wireguard/lolli_psk" = {};
      "wireguard/ramped_psk" = {};
      "wireguard/timetrad_psk" = {};
      "wireguard/treebeard_psk" = {};
      "wireguard/wg1_conf" = {};
      "wpa_supplicant" = {};
    };
  };

  system.activationScripts = {
    fix-acl-cgit-home-nipsy = ''
      ${pkgs.acl}/bin/setfacl -m u:cgit:--x /home/nipsy
    '';
  };

  system.stateVersion = "23.11";

  systemd.services = {

    "lidarr" = {
      after = [ "network.target" ];
      description = "Lidarr Daemon";
      serviceConfig = {
        User = "nipsy";
        Group = "nipsy";
        Restart = "always";
        RestartSec= 5;
        Type = "simple";
        ExecStart = "${pkgs.lidarr}/bin/Lidarr -nobrowser";
        TimeoutStopSec = 20;
        PIDFile = "/home/nipsy/.config/Lidarr/lidarr.pid";
      };
      wantedBy = [ "multi-user.target" ];
    };

    "nftables-extra" = let rules_script = ''
        ${pkgs.nftables}/bin/nft insert rule inet nixos-fw input 'iifname "wlp5s0" tcp dport { http, https } counter accept # 80, 443'
        ${pkgs.nftables}/bin/nft insert rule inet nixos-fw input 'iifname "wlp5s0" udp dport { netbios-ns, netbios-dgm } counter accept # 137, 138'
        ${pkgs.nftables}/bin/nft insert rule inet nixos-fw input 'iifname "wlp5s0" tcp dport { netbios-ssn, microsoft-ds } counter accept # 139, 445'
        ${pkgs.nftables}/bin/nft insert rule inet nixos-fw input 'iifname "wlp5s0" tcp dport 2049 counter accept'
        ${pkgs.nftables}/bin/nft insert rule inet nixos-fw input 'iifname "wlp5s0" udp dport { 2456, 2457 } counter accept # Valheim dedicated server'
        ${pkgs.nftables}/bin/nft insert rule inet nixos-fw input 'iifname "wlp5s0" udp dport 5121 counter accept # Neverwinter Nights Server'
        ${pkgs.nftables}/bin/nft insert rule inet nixos-fw input 'iifname "veth.host" tcp dport { 7878, 8080, 8686, 8787, 8989 } counter accept # Radarr, Sabnzb, Lidarr, Sonarr, Readarr'
        ${pkgs.nftables}/bin/nft insert rule inet nixos-fw input 'iifname "wlp5s0" tcp dport { 7878, 8080, 8686, 8787, 8989 } counter accept # Radarr, Sabnzb, Lidarr, Sonarr, Readarr'
        ${pkgs.nftables}/bin/nft insert rule inet nixos-fw input 'iifname "wlp5s0" udp dport 15637 counter accept # Enshrouded'
        ${pkgs.nftables}/bin/nft insert rule inet nixos-fw input 'iifname "wlp5s0" ip saddr 192.168.1.0/24 udp dport { 27031, 27036 } counter accept # Steam Remote Play'
        ${pkgs.nftables}/bin/nft insert rule inet nixos-fw input 'iifname "wlp5s0" ip saddr 192.168.1.0/24 tcp dport { 27036, 27037 } counter accept # Steam Remote Play'
        ${pkgs.nftables}/bin/nft insert rule inet nixos-fw input 'iifname "wlp5s0" udp dport 51820 counter accept # WireGuard'
        ${pkgs.nftables}/bin/nft -f ${config.sops.secrets."nftables/ssh".path}
      ''; in {
        description = "nftables extra firewall rules";
        reload = rules_script;
        script = rules_script;
        serviceConfig = {
          RemainAfterExit = true;
          Type = "oneshot";
        };
        unitConfig = {
          ConditionPathExists = [
            config.sops.secrets."nftables/ssh".path
          ];
          ReloadPropagatedFrom = "nftables.service";
        };
        wantedBy = [ "multi-user.target" ];
        after = [ "nftables.service" ];
        partOf = [ "nftables.service" ];
    };

    "prowlarr" = {
      after = [ "vpn.service" ];
      description = "Prowlarr Daemon";
      serviceConfig = {
        User = "nipsy";
        Group = "nipsy";
        Restart = "always";
        RestartSec= 5;
        Type = "simple";
        ExecStart = "${pkgs.prowlarr}/bin/Prowlarr -nobrowser";
        TimeoutStopSec = 20;
        PIDFile = "/home/nipsy/.config/Prowlarr/prowlarr.pid";
        NetworkNamespacePath = "/run/netns/vpn";
      };
      wantedBy = [ "multi-user.target" ];
    };

    "qbittorrent" = {
      after = [ "vpn.service" ];
      description = "qBittorrent-nox service";
      serviceConfig = {
        User = "nipsy";
        Group = "nipsy";
        Type = "simple";
        ExecStart = "${pkgs.qbittorrent-nox}/bin/qbittorrent-nox";
        TimeoutStopSec = 1800;
        NetworkNamespacePath = "/run/netns/vpn";
      };
      wantedBy = [ "multi-user.target" ];
    };

    "radarr" = {
      after = [ "network.target" ];
      description = "Radarr Daemon";
      serviceConfig = {
        User = "nipsy";
        Group = "nipsy";
        Restart = "always";
        RestartSec= 5;
        Type = "simple";
        ExecStart = "${pkgs.radarr}/bin/Radarr -nobrowser";
        TimeoutStopSec = 20;
        PIDFile = "/home/nipsy/.config/Radarr/radarr.pid";
      };
      wantedBy = [ "multi-user.target" ];
    };

    "readarr" = {
      after = [ "network.target" ];
      description = "Readarr Daemon";
      serviceConfig = {
        User = "nipsy";
        Group = "nipsy";
        Restart = "always";
        RestartSec= 5;
        Type = "simple";
        ExecStart = "${pkgs.readarr}/bin/Readarr -nobrowser";
        TimeoutStopSec = 20;
        PIDFile = "/home/nipsy/.config/Readarr/readarr.pid";
      };
      wantedBy = [ "multi-user.target" ];
    };

    "sonarr" = {
      after = [ "network.target" ];
      description = "Sonarr Daemon";
      serviceConfig = {
        User = "nipsy";
        Group = "nipsy";
        Restart = "always";
        RestartSec= 5;
        Type = "simple";
        ExecStart = "${pkgs.sonarr}/bin/Sonarr -nobrowser";
        TimeoutStopSec = 20;
        PIDFile = "/home/nipsy/.config/Sonarr/sonarr.pid";
      };
      wantedBy = [ "multi-user.target" ];
    };

    "vpn" = {
      after = [ "network.target" ];
      description = "VPN service";
      serviceConfig = {
        RemainAfterExit = true;
        Type = "oneshot";
        ExecStart = "/root/bin/vpnctl start";
      };
      unitConfig = {
        ConditionPathExists = [
          "/root/bin/vpnctl"
        ];
      };
      wantedBy = [ "multi-user.target" ];
    };

  };

  systemd.paths."nftables-extra" = {
    pathConfig = {
      PathExists = [
        config.sops.secrets."nftables/ssh".path
      ];
    };
    wantedBy = [ "multi-user.target" ];
  };
}