{ pkgs, ... }:
let
  deviceName = "rp0";

  server = {
    ip = "fe80::1";
    wg = {
      public = "mQufmDFeQQuU/fIaB2hHgluhjjm1ypK4hJr1cW3WqAw=";
      secret = "4N5Y1dldqrpsbaEiY8O0XBUGUFf8vkvtBtm8AoOX7Eo=";
      listen = 10000;
    };
  };
  client = {
    ip = "fe80::2";
    wg = {
      public = "Mb3GOlT7oS+F3JntVKiaD7SpHxLxNdtEmWz/9FMnRFU=";
      secret = "uC5dfGMv7Oxf5UDfdPkj6rZiRZT2dRWp5x8IQxrNcUE=";
    };
  };
in
{
  name = "rosenpass";

  nodes =
    let
      shared =
        peer:
        { config, modulesPath, ... }:
        {
          imports = [ "${modulesPath}/services/networking/rosenpass.nix" ];

          boot.kernelModules = [ "wireguard" ];

          services.rosenpass = {
            enable = true;
            defaultDevice = deviceName;
            settings = {
              verbosity = "Verbose";
              public_key = "/etc/rosenpass/pqpk";
              secret_key = "/etc/rosenpass/pqsk";
            };
          };

          networking.firewall.allowedUDPPorts = [ 9999 ];

          systemd.network = {
            enable = true;
            networks."rosenpass" = {
              matchConfig.Name = deviceName;
              networkConfig.IPv4Forwarding = true;
              networkConfig.IPv6Forwarding = true;
              address = [ "${peer.ip}/64" ];
            };

            netdevs."10-rp0" = {
              netdevConfig = {
                Kind = "wireguard";
                Name = deviceName;
              };
              wireguardConfig.PrivateKeyFile = "/etc/wireguard/wgsk";
            };
          };

          environment.etc."wireguard/wgsk" = {
            text = peer.wg.secret;
            user = "systemd-network";
            group = "systemd-network";
          };
        };
    in
    {
      server = {
        imports = [ (shared server) ];

        networking.firewall.allowedUDPPorts = [ server.wg.listen ];

        systemd.network.netdevs."10-${deviceName}" = {
          wireguardConfig.ListenPort = server.wg.listen;
          wireguardPeers = [
            {
              AllowedIPs = [ "::/0" ];
              PublicKey = client.wg.public;
            }
          ];
        };

        services.rosenpass.settings = {
          listen = [ "0.0.0.0:9999" ];
          peers = [
            {
              public_key = "/etc/rosenpass/peers/client/pqpk";
              peer = client.wg.public;
            }
          ];
        };
      };
      client = {
        imports = [ (shared client) ];

        systemd.network.netdevs."10-${deviceName}".wireguardPeers = [
          {
            AllowedIPs = [ "::/0" ];
            PublicKey = server.wg.public;
            Endpoint = "server:${builtins.toString server.wg.listen}";
          }
        ];

        services.rosenpass.settings.peers = [
          {
            public_key = "/etc/rosenpass/peers/server/pqpk";
            endpoint = "server:9999";
            peer = server.wg.public;
          }
        ];
      };
    };

  testScript =
    { ... }:
    ''
      from os import system

      # Full path to rosenpass in the store, to avoid fiddling with `$PATH`.
      rosenpass = "${pkgs.rosenpass}/bin/rosenpass"

      # Path in `/etc` where keys will be placed.
      etc = "/etc/rosenpass"

      start_all()

      for machine in [server, client]:
          machine.wait_for_unit("multi-user.target")

      # Gently stop Rosenpass to avoid crashes during key generation/distribution.
      for machine in [server, client]:
          machine.execute("systemctl stop rosenpass.service")

      for (name, machine, remote) in [("server", server, client), ("client", client, server)]:
          pk, sk = f"{name}.pqpk", f"{name}.pqsk"
          system(f"{rosenpass} gen-keys --force --secret-key {sk} --public-key {pk}")
          machine.copy_from_host(sk, f"{etc}/pqsk")
          machine.copy_from_host(pk, f"{etc}/pqpk")
          remote.copy_from_host(pk, f"{etc}/peers/{name}/pqpk")

      for machine in [server, client]:
          machine.execute("systemctl start rosenpass.service")

      for machine in [server, client]:
          machine.wait_for_unit("rosenpass.service")

      with subtest("ping"):
          client.succeed("ping -c 2 -i 0.5 ${server.ip}%${deviceName}")

      with subtest("preshared-keys"):
          # Rosenpass works by setting the WireGuard preshared key at regular intervals.
          # Thus, if it is not active, then no key will be set, and the output of `wg show` will contain "none".
          # Otherwise, if it is active, then the key will be set and "none" will not be found in the output of `wg show`.
          for machine in [server, client]:
              machine.wait_until_succeeds("wg show all preshared-keys | grep --invert-match none", timeout=5)
    '';

  # NOTE: Below configuration is for "interactive" (=developing/debugging) only.
  interactive.nodes =
    let
      inherit (import ./ssh-keys.nix pkgs) snakeOilPublicKey snakeOilPrivateKey;

      sshAndKeyGeneration = {
        services.openssh.enable = true;
        users.users.root.openssh.authorizedKeys.keys = [ snakeOilPublicKey ];
        environment.systemPackages = [
          (pkgs.writeShellApplication {
            name = "gen-keys";
            runtimeInputs = [ pkgs.rosenpass ];
            text = ''
              HOST="$(hostname)"
              if [ "$HOST" == "server" ]
              then
                PEER="client"
              else
                PEER="server"
              fi

              # Generate keypair.
              mkdir -vp /etc/rosenpass/peers/$PEER
              rosenpass gen-keys --force --secret-key /etc/rosenpass/pqsk --public-key /etc/rosenpass/pqpk

              # Set up SSH key.
              mkdir -p /root/.ssh
              cp ${snakeOilPrivateKey} /root/.ssh/id_ecdsa
              chmod 0400 /root/.ssh/id_ecdsa

              # Copy public key to other peer.
              # shellcheck disable=SC2029
              ssh -o StrictHostKeyChecking=no $PEER "mkdir -pv /etc/rosenpass/peers/$HOST"
              scp /etc/rosenpass/pqpk "$PEER:/etc/rosenpass/peers/$HOST/pqpk"
            '';
          })
        ];
      };

      # Use kmscon <https://www.freedesktop.org/wiki/Software/kmscon/>
      # to provide a slightly nicer console, and while we're at it,
      # also use a nice font.
      # With kmscon, we can for example zoom in/out using [Ctrl] + [+]
      # and [Ctrl] + [-]
      niceConsoleAndAutologin.services.kmscon = {
        enable = true;
        autologinUser = "root";
        fonts = [
          {
            name = "Fira Code";
            package = pkgs.fira-code;
          }
        ];
      };
    in
    {
      server = sshAndKeyGeneration // niceConsoleAndAutologin;
      client = sshAndKeyGeneration // niceConsoleAndAutologin;
    };
}
