kittybox:
{ lib, ... }: let
  hosts = ''
    192.168.2.101 kittybox.test
    192.168.2.102 another.test
  '';
in {
  name = "nixos-kittybox";

  nodes = {
    kittybox = { config, pkgs, lib, ... }: {
      imports = [ kittybox.nixosModules.default ];

      services.postgresql = {
        enable = true;
        ensureDatabases = ["kittybox"];
        ensureUsers = [ {
          name = "kittybox";
          ensurePermissions = {
            "DATABASE kittybox" = "ALL PRIVILEGES";
          };
        } ];
      };

      networking = {
        interfaces.eth1 = {
          ipv4.addresses = [
            { address = "192.168.2.101"; prefixLength = 24; }
          ];
        };
        extraHosts = hosts;
        firewall.allowedTCPPorts = [ 443 ];
        firewall.allowedUDPPorts = [ 443 ];
      };


      services.kittybox = {
        enable = true;
        logLevel = "info,kittybox=debug,retainer::cache=warn,h2=warn,rustls=warn";
        backendUri = "postgres://localhost?host=/run/postgresql&dbname=kittybox";
        jobQueueUri = config.services.kittybox.backendUri;
      };

      systemd.services.kittybox.wants = [ "postgresql.service" ];
      systemd.services.kittybox.after = [ "postgresql.service" ];
      systemd.services.kittybox.environment = {
        "KITTYBOX_CUSTOM_PKI_ROOTS" = ./tls/rootCA.pem;
      };

      environment.systemPackages = with pkgs; [
        xh
      ];

      services.nginx = {
        enable = true;
        recommendedProxySettings = true;
        virtualHosts = {
          "kittybox.test" = {
            forceSSL = true;
            sslCertificate = ./tls/kittybox.test.pem;
            sslCertificateKey = ./tls/kittybox.test-key.pem;
            locations = {
              "/" = {
                proxyPass = "http://localhost:8080";
              };
            };
          };
        };
      };

      security.pki.certificates = [
        (builtins.readFile ./tls/rootCA.pem)
      ];
    };

    another = { config, pkgs, lib, ... }: {
      networking = {
        interfaces.eth1 = {
          ipv4.addresses = [
            { address = "192.168.2.102"; prefixLength = 24; }
          ];
        };
        extraHosts = hosts;
        firewall.allowedTCPPorts = [ 443 ];
        firewall.allowedUDPPorts = [ 443 ];
      };

      services.nginx = {
        enable = true;
        virtualHosts = {
          "another.test" = {
            forceSSL = true;
            sslCertificate = ./tls/another.test.pem;
            sslCertificateKey = ./tls/another.test-key.pem;
            locations = {
              "/" = {
                root = ./webmention-test;
              };
            };
          };
        };
      };

      environment.systemPackages = with pkgs; [
        xh
      ];

      security.pki.certificates = [
        (builtins.readFile ./tls/rootCA.pem)
      ];
    };
  };

  testScript = ''
    import json
    import shlex
    import time

    post_mf2 = {
        "type": ["h-entry"],
        "properties": {
            "uid": ["https://kittybox.test/posts/test-post"],
            "url": ["https://kittybox.test/posts/test-post"],
            "published": ["2023-07-22T14:04:53+0300"],
            "content": [{"html": "<p>Hello! This is a test post.</p>"}],
            "author": ["https://kittybox.test/"],
        }
    }

    start_all()

    with subtest("Verify that Kittybox started correctly..."):
        kittybox.wait_for_unit("default.target")
        kittybox.succeed("xh --no-check-status https://kittybox.test/.kittybox/micropub")

    with subtest("Onboarding should correctly work..."):
        kittybox.copy_from_host("${./onboarding.json}", "/root/onboarding.json")
        kittybox.succeed("xh --follow https://kittybox.test/.kittybox/onboarding -j @/root/onboarding.json")
        # Testing for a known string is the easiest way to determine that the onboarding worked
        kittybox.succeed("xh https://kittybox.test/ | grep 'vestige of the past long gone'")

    with subtest("The other host should also be reachable..."):
        another.wait_for_unit("default.target")
        another.succeed("xh https://another.test/ | grep 'This is a test webmention.'")

    with subtest("Kittybox accepts a webmention to a valid post..."):
        # Note: we don't really have a way to "authenticate" here.
        # Let's insert the post manually.
        print(kittybox.succeed("sudo -u postgres psql kittybox -c \"INSERT INTO kittybox.mf2_json (uid, mf2, owner) VALUES ('https://kittybox.test/posts/test-post', '" + json.dumps(post_mf2).replace("\"", "\\\"").replace("'", "'" * 2) + "', 'kittybox.test') RETURNING uid\""))
        print(kittybox.succeed("sudo -u postgres psql -A kittybox -c \"SELECT mf2 FROM kittybox.mf2_json WHERE uid = 'https://kittybox.test/posts/test-post'\""))
        kittybox.succeed("xh --verify ${./tls/rootCA.pem} https://kittybox.test/posts/test-post")

        another.succeed("xh --verify ${./tls/rootCA.pem} https://kittybox.test/.kittybox/webmention --form source=https://another.test/index.html target=https://kittybox.test/posts/test-post")
        # Wait a while to let the async tasks settle...
        time.sleep(2)
        # Ensure the webmention has propagated
        # Kittybox doesn't fully render them yet, but the counters are there
        kittybox.succeed("xh --verify ${./tls/rootCA.pem} https://kittybox.test/posts/test-post | grep " + shlex.quote('<span class="icon" aria-label="replies">💬</span><span class="counter">1</span>'))

'';
}