{ lib, pkgs, config, assignments, ... }:
let
  inherit (lib) mkMerge mkIf;
  inherit (lib.my) networkdAssignment;
  inherit (lib.my.c.colony) prefixes;

  wg = {
    keyFile = "jackflix/airvpn-privkey";
    pskFile = "jackflix/airvpn-psk";
    fwMark = 42;
    routeTable = 51820;
  };

  # Forwarded in AirVPN config
  transmissionPeerPort = 28457;
in
{
  config = mkMerge [
    {
      my = {
        secrets = {
          files."${wg.keyFile}" = {
            group = "systemd-network";
            mode = "440";
          };
          files."${wg.pskFile}" = {
            group = "systemd-network";
            mode = "440";
          };
        };

        firewall = {
          extraRules = ''
            # Make sure that VPN connections are dropped (except for the Transmission port)
            table inet filter {
              chain tcp-ext {
                tcp dport ${toString transmissionPeerPort} accept
                iifname vpn return

                tcp dport { 19999, 9091, 9117, 7878, 8989, 8096, 2342 } accept
                return
              }
              chain input {
                tcp flags & (fin|syn|rst|ack) == syn ct state new jump tcp-ext
              }
            }
          '';
        };
      };

      environment.systemPackages = with pkgs; [
        wireguard-tools
      ];

      services = {
        transmission.settings.peer-port = transmissionPeerPort;
      };

      systemd = {
        network = {
          netdevs."30-vpn" = with wg; {
            netdevConfig = {
              Name = "vpn";
              Kind = "wireguard";
              # Specified by AirVPN
              MTUBytes = "1320";
            };
            wireguardConfig = {
              PrivateKeyFile = config.age.secrets."${keyFile}".path;
              FirewallMark = fwMark;
              RouteTable = routeTable;
            };
            wireguardPeers = [
              # AirVPN NL
              {
                Endpoint = "2a00:1678:1337:2329:e5f:35d4:4404:ef9f:1637";
                PublicKey = "PyLCXAQT8KkM4T+dUsOQfn+Ub3pGxfGlxkIApuig+hk=";
                PresharedKeyFile = config.age.secrets."${pskFile}".path;
                AllowedIPs = [ "0.0.0.0/0" "::/0" ];
              }
            ];
          };

          networks = {
            "80-container-host0" = mkMerge [
              (networkdAssignment "host0" assignments.internal)
              {
                networkConfig.DNSDefaultRoute = false;
              }
            ];
            "90-vpn" = with wg; {
              matchConfig.Name = "vpn";
              address = [ "10.182.97.37/32" "fd7d:76ee:e68f:a993:735d:ef5e:6907:b122/128" ];
              dns = [ "10.128.0.1" "fd7d:76ee:e68f:a993::1" ];
              routingPolicyRules = [
                {
                  Family = "both";
                  SuppressPrefixLength = 0;
                  Table = "main";
                  Priority = 100;
                }

                {
                  From = prefixes.all.v4;
                  Table = "main";
                  Priority = 100;
                }
                {
                  To = prefixes.all.v4;
                  Table = "main";
                  Priority = 100;
                }

                {
                  From = prefixes.all.v6;
                  Table = "main";
                  Priority = 100;
                }
                {
                  To = prefixes.all.v6;
                  Table = "main";
                  Priority = 100;
                }

                {
                  Family = "both";
                  InvertRule = true;
                  FirewallMark = fwMark;
                  Table = routeTable;
                  Priority = 110;
                }
              ];
            };
          };
        };
      };
    }
    (mkIf config.my.build.isDevVM {
      virtualisation = {
        forwardPorts = [
          # Transmission
          { from = "host"; host.port = 9091; guest.port = 9091; }
          # Jackett
          { from = "host"; host.port = 9117; guest.port = 9117; }
          # Radarr
          { from = "host"; host.port = 7878; guest.port = 7878; }
          # Sonarr
          { from = "host"; host.port = 8989; guest.port = 8989; }
          # Jellyfin
          { from = "host"; host.port = 8096; guest.port = 8096; }
        ];
      };
    })
  ];
}
