{
  config,
  pkgs,
  lib,
  ...
}:

let
  wireguard_port = 1194;

in
{
  # Enable systemd-networkd
  networking = {
    hostName = "zion";
    hostId = "760bfad7";
    useDHCP = false;
    useNetworkd = true;
    dhcpcd.enable = false;
  };
  systemd.network.wait-online.enable = false;

  # Assign a static IP
  systemd.network.networks."24-home" = {
    name = "enp2s0";
    matchConfig.Name = "enp2s0";
    address = [ "192.168.128.2/23" ];
    gateway = [ "192.168.128.1" ];
    dns = [
      "1.1.1.1"
      "9.9.9.9"
    ];
    networkConfig.DNSSEC = "no";
  };

  # Dynamic DNS configuration
  services.inadyn = {
    enable = true;
    interval = "*:0/30";
    settings.provider."duckdns" = {
      hostname = "coolneng.duckdns.org";
      include = config.age.secrets.inadyn-duckdns.path;
    };
  };

  # Dynamic DNS configuration for Porkbun
  # NOTE Temporary workaround until Inadyn fixes the Porkbun module
  services.oink = {
    enable = true;
    settings = {
      apiKey = "PLACEHOLDER";
      secretApiKey = "PLACEHOLDER";
      interval = 1800;
    };
    domains = [
      {
        domain = "psydnd.org";
        subdomain = "";
      }
    ];
  };
  # NOTE Load credentials using environment variables
  systemd.services.oink.serviceConfig.EnvironmentFile = config.age.secrets.inadyn-porkbun.path;

  # Firewall configuration
  networking.firewall = {
    allowedTCPPorts = [
      80 # HTTP
      443 # HTTPS
      53 # DNS
      8448 # Matrix
      1883 # MQTT
    ];
    allowedUDPPorts = [
      wireguard_port # Wireguard
      53 # DNS
    ];
    extraCommands = ''
      iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o ${
        config.systemd.network.networks."24-home".name
      } -j MASQUERADE
      ip6tables -t nat -A POSTROUTING -s fd00::0/128 -o ${
        config.systemd.network.networks."24-home".name
      } -j MASQUERADE
    '';
  };

  # Wireguard setup
  systemd.network.netdevs."wg0" = {
    netdevConfig = {
      Kind = "wireguard";
      Name = "wg0";
    };
    wireguardConfig = {
      ListenPort = wireguard_port;
      PrivateKeyFile = config.age.secrets.wireguard.path;
    };
    wireguardPeers = [
      # panacea
      {
        PublicKey = "XMkTztU2Y8hw6Fu/2o4Gszij+EmNacvFMXuZyHS1n38=";
        AllowedIPs = [
          "10.8.0.2/32"
          "fd00::2/128"
        ];
      }
      # caravanserai
      {
        PublicKey = "mCsTj09H7lfDDs8vMQkJOlItHtHQ6MPUyfGO5ZjBbVs=";
        AllowedIPs = [
          "10.8.0.3/32"
          "fd00::3/128"
        ];
      }
    ];
  };

  systemd.network.networks."wg0" = {
    matchConfig.Name = "wg0";
    networkConfig = {
      Address = [
        "10.8.0.1/24"
        "fd00::1/128"
      ];
      IPv4Forwarding = true;
      IPv6Forwarding = true;
    };
  };

  # DNS server with ad-block
  services.dnsmasq = {
    enable = true;
    settings = {
      domain-needed = true;
      bogus-priv = true;
      no-resolv = true;

      listen-address = [
        "127.0.0.1"
        "192.168.128.2"
        "10.8.0.1"
        "::1"
        "fd00::1"
      ];
      bind-interfaces = true;
      server = [ "127.0.0.1#43" ];

      cache-size = 10000;
      local-ttl = 300;

      conf-file = "${pkgs.dnsmasq}/share/dnsmasq/trust-anchors.conf";
      dnssec = false;
    };
  };

  # Encrypted DNS
  services.dnscrypt-proxy2 = {
    enable = true;
    upstreamDefaults = true;
    settings = {
      listen_addresses = [
        "127.0.0.1:43"
        "[::1]:43"
      ];
      sources.public-resolvers = {
        urls = [ "https://download.dnscrypt.info/resolvers-list/v3/public-resolvers.md" ];
        cache_file = "/var/lib/dnscrypt-proxy2/public-resolvers.md";
        minisign_key = "RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3";
      };
      blocked_names.blocked_names_file = "/var/lib/dnscrypt-proxy/blocklist.txt";
    };
  };

}