{
  lib,
  pkgs,
  outputs,
  config,
  modulesPath,
  ...
}: {
  imports = [
    # inputs.nixos-hardware.nixosModules.raspberry-pi-4
    (modulesPath + "/installer/sd-card/sd-image-aarch64.nix")
    outputs.nixosModules.vpn-ip

    ./hardware-configuration.nix

    # Import shared settings
  ];

  nixpkgs.overlays = [
    (final: super: {
      makeModulesClosure = x:
        super.makeModulesClosure (x // {allowMissing = true;});
    })
  ];
  programs = {
    # Allow executing of anything on the system with a , eg: , python executes python from the nix store even if not in $PATH currently
    command-not-found.enable = lib.mkForce false;
    nix-index.enable = true;
    nix-index-database.comma.enable = true;
  };
  services = {
    automatic-timezoned.enable = true;

    # stubby = {
    #   enable = true;
    #   settings =
    #     pkgs.stubby.passthru.settingsExample
    #     // {
    #       upstream_recursive_servers = [
    #         {
    #           address_data = "94.140.14.49";
    #           tls_auth_name = "4b921896.d.adguard-dns.com";
    #           tls_pubkey_pinset = [
    #             {
    #               digest = "sha256";
    #               value = "19HOzAWb2bgl7bo/b4Soag+5luf7bo6vlDN8W812k4U=";
    #             }
    #           ];
    #         }
    #         {
    #           address_data = "94.140.14.59";
    #           tls_auth_name = "4b921896.d.adguard-dns.com";
    #           tls_pubkey_pinset = [
    #             {
    #               digest = "sha256";
    #               value = "19HOzAWb2bgl7bo/b4Soag+5luf7bo6vlDN8W812k4U=";
    #             }
    #           ];
    #         }
    #         {
    #           address_data = "2a10:50c0:0:0:0:0:ded:ff";
    #           tls_auth_name = "4b921896.d.adguard-dns.com";
    #           tls_pubkey_pinset = [
    #             {
    #               digest = "sha256";
    #               value = "19HOzAWb2bgl7bo/b4Soag+5luf7bo6vlDN8W812k4U=";
    #             }
    #           ];
    #         }
    #         {
    #           address_data = "2a10:50c0:0:0:0:0:dad:ff";
    #           tls_auth_name = "4b921896.d.adguard-dns.com";
    #           tls_pubkey_pinset = [
    #             {
    #               digest = "sha256";
    #               value = "19HOzAWb2bgl7bo/b4Soag+5luf7bo6vlDN8W812k4U=";
    #             }
    #           ];
    #         }
    #       ];
    #     };
    # };

    openssh = {
      enable = true;
      # require public key authentication for better security
      settings.PasswordAuthentication = false;
      settings.KbdInteractiveAuthentication = false;
      settings.PermitRootLogin = "no";
    };

    davfs2.enable = true;

    aria2 = {
      enable = true;
      settings = {
        dir = "/var/lib/media";
        rpc-listen-port = 6969;
      };
      rpcSecretFile = config.sops.secrets."rpcSecret".path;
    };
    dnsmasq = {
      enable = true;
      settings = {
        interface = "wg1";
      };
    };
  };

  sops = {
    # users.users = {
    #   ombi.extraGroups = ["radarr" "sonarr" "aria2"];
    # };
    # services.ombi = {
    #   enable = true;
    #   port = 2368;
    # };

    # users.users = {
    #   radarr.extraGroups = ["aria2"];
    #   sonarr.extraGroups = ["aria2"];
    # };

    # services = {
    #   #uses port 7878
    #   radarr.enable = true;
    #   #uses port 8989
    #   sonarr.enable = true;
    #   prowlarr.enable = true;
    # };

    secrets."webdav-secret" = {
      mode = "0600";
      path = "/etc/davfs2/secrets";
      owner = config.users.users.root.name;
    };

    secrets."rpcSecret".mode = "0440";
    secrets."rpcSecret".owner = config.users.users.aria2.name;

    secrets."protonvpn-priv-key".mode = "0440";
    secrets."protonvpn-priv-key".owner = config.users.users.root.name;
  };
  boot = {
    kernelPackages = lib.mkForce pkgs.linuxPackages_latest;

    initrd.kernelModules = ["vc4" "bcm2835_dma" "i2c_bcm2835" "cma=256M" "console=tty0"];

    kernel.sysctl = {
      "net.ipv4.ip_forward" = 1;
      "net.ipv6.conf.all.forwarding" = 1;
    };
  };

  sdImage.compressImage = false;

  services.vpn-ip = {
    enable = false;
  };

  networking = {
    hostName = "wheatley";

    networkmanager.enable = true;

    # Disable NetworkManager's internal DNS resolution
    networkmanager.dns = "none";

    # These options are unnecessary when managing DNS ourselves
    useDHCP = false;
    dhcpcd.enable = false;

    # Configure DNS servers manually (this example uses Cloudflare and Google DNS)
    # IPv6 DNS servers can be used here as well.
    nameservers = [
      # "127.0.0.1"
      # "::1"
      "94.140.14.49"
      "94.140.14.59"
      "2a10:50c0:0:0:0:0:ded:ff"
      "2a10:50c0:0:0:0:0:ded:ff"
    ];

    wireguard.enable = true;

    wg-quick.interfaces = {
      #   # "wg0" is the network interface name. You can name the interface arbitrarily.
      #   wg0 = {
      #     autostart = true;
      #     # Determines the IP address and subnet of the server's end of the tunnel interface.
      #     address = ["10.2.0.2/32"];

      #     # The port that WireGuard listens to. Must be accessible by the client.
      #     listenPort = 51820;

      #     dns = ["10.2.0.1"];
      #     # Path to the private key file.
      #     #
      #     # Note: The private key can also be included inline via the privateKey option,
      #     # but this makes the private key world-readable; thus, using privateKeyFile is
      #     # recommended.
      #     privateKeyFile = config.sops.secrets."protonvpn-priv-key".path;

      #     peers = [
      #       # List of allowed peers.
      #       {
      #         # Feel free to give a meaning full name
      #         # Public key of the peer (not a file path).
      #         publicKey = "/i7jCNpcqVBUkY07gVlILN4nFdvZHmxvreAOgLGoZGg=";
      #         # List of IPs assigned to this peer within the tunnel subnet. Used to configure routing.
      #         allowedIPs = ["0.0.0.0/0"];
      #         endpoint = "146.70.86.114:51820";
      #       }
      #     ];
      #   };

      # wg public key for host: A02sO7uLdgflhPIRd0cbJONIaPP4z8HTxDkmX4NegFg=
      # TODO: generate this dynamically based on other hosts
      wg1 = {
        # Determines the IP address and subnet of the server's end of the tunnel interface.
        address = ["10.0.0.1/24" "fdc9:281f:04d7:9ee9::1/64"];

        # The port that WireGuard listens to. Must be accessible by the client.
        listenPort = 51821;

        # This allows the wireguard server to route your traffic to the internet and hence be like a VPN
        postUp = ''
          ${pkgs.iptables}/bin/iptables -A FORWARD -i wg0 -j ACCEPT
          ${pkgs.iptables}/bin/iptables -t nat -A POSTROUTING -s 10.0.0.1/24 -o eth0 -j MASQUERADE
          ${pkgs.iptables}/bin/ip6tables -A FORWARD -i wg0 -j ACCEPT
          ${pkgs.iptables}/bin/ip6tables -t nat -A POSTROUTING -s fdc9:281f:04d7:9ee9::1/64 -o eth0 -j MASQUERADE
        '';

        # Undo the above
        preDown = ''
          ${pkgs.iptables}/bin/iptables -D FORWARD -i wg0 -j ACCEPT
          ${pkgs.iptables}/bin/iptables -t nat -D POSTROUTING -s 10.0.0.1/24 -o eth0 -j MASQUERADE
          ${pkgs.iptables}/bin/ip6tables -D FORWARD -i wg0 -j ACCEPT
          ${pkgs.iptables}/bin/ip6tables -t nat -D POSTROUTING -s fdc9:281f:04d7:9ee9::1/64 -o eth0 -j MASQUERADE
        '';

        privateKeyFile = lib.mkForce config.sops.secrets."wg-private-key".path;

        peers = [
          {
            #GLaDOS public key
            publicKey = "yieF2yQptaE3jStoaGytUnN+HLxyVhFBZIUOGUNAV38=";
            allowedIPs = ["10.0.0.2/32" "fdc9:281f:04d7:9ee9::2/128"];
          }
          {
            #EDI public key
            publicKey = "i4nDZbU+a2k5C20tFJRNPVE1vhYKJwhoqGHEdeC4704=";
            allowedIPs = ["10.0.0.3/32" "fdc9:281f:04d7:9ee9::3/128"];
          }
          {
            #Shodan public key
            publicKey = "Zah2nZDaHF8jpP5AtMA5bhE7t38fMB2UHzbXAc96/jw=";
            allowedIPs = ["10.0.0.4/32" "fdc9:281f:04d7:9ee9::3/128"];
          }
          {
            #ADA public key
            publicKey = "SHu7xxRVWuqp4U4uipMoITKrFPWZATGsJevUeqBSzWo=";
            allowedIPs = ["10.0.0.5/32" "fdc9:281f:04d7:9ee9::3/128"];
          }
          #Queen public key: FVTrYM7S2Ev2rGrYrHsG2et1/SU3UjEBQH2AOen4+04=
        ];
      };
    };
    nat = {
      # enable NAT
      enable = true;
      externalInterface = "end0";
      internalInterfaces = ["wg1"];
    };
    firewall = {
      enable = true;
      allowPing = false;
      allowedTCPPorts = [
        22 # SSH
        5349 # STUN tls
        5350 # STUN tls alt
        80 # http
        443 # https
        51821 # wg
        7878
        53 # dnsmasq
      ];
      allowedUDPPorts = [
        53 #dnsmasq
      ];
      allowedUDPPortRanges = [
        {
          from = 51820;
          to = 51822; # wg
        }
        {
          from = 49152;
          to = 49999;
        } # TURN relay
      ];
    };
  };
  systemd.mounts = [
    {
      enable = true;
      description = "Webdav mount point";
      after = ["network-online.target"];
      wants = ["network-online.target"];

      what = "https://nextcloud.gladtherescake.eu/remote.php/dav/files/GLaDTheresCake";
      where = "/home/kodi/nextcloud";
      options = "uid=1002,gid=100,file_mode=0664,dir_mode=2775";
      type = "davfs";
    }
  ];

  environment.systemPackages = [
    (pkgs.kodi.withPackages (kodiPkgs:
      with kodiPkgs; [
        steam-controller
        invidious
        netflix
        upnext
        sponsorblock
        sendtokodi
        jellyfin
      ]))
    pkgs.iptables
  ];

  users.extraUsers.kodi.isNormalUser = true;
  services.cage.user = "kodi";
  services.cage.program = "${pkgs.kodi-wayland}/bin/kodi-standalone";
  services.cage.enable = true;

  system.stateVersion = "25.05";
  nixpkgs.hostPlatform = lib.mkForce "aarch64-linux";
}