{
  pkgs,
  lib,
  config,
  ...
}:
let
  matrixLib = pkgs.callPackage ./lib.nix { };

  cfg = config.services.matrix-hookshot;
  conduitCfg = config.services.matrix-conduit;

  domain = conduitCfg.settings.global.server_name;

  registration = matrixLib.writeRegistrationScript {
    id = "matrix-hookshot";
    url = "http://127.0.0.1:9993";
    sender_localpart = "hookshot";

    namespaces = {
      aliases = [ ];
      rooms = [ ];
      users = [
        {
          regex = "@${cfg.settings.generic.userIdPrefix}.*:${domain}";
          exclusive = true;
        }
      ];
    };

    # Encryption support
    extraSettings = {
      "de.sorunome.msc2409.push_ephemeral" = true;
      push_ephemeral = true;
      "org.matrix.msc3202" = true;
    };

    runtimeRegistration = "${cfg.registrationFile}";
  };
in
{
  systemd.services.matrix-hookshot = {
    serviceConfig = {
      Type = lib.mkForce "exec";

      LoadCredential = "matrix-hookshot:/run/secrets/matrix-hookshot";
      inherit (registration) ExecStartPre;

      # Some library in matrix-hookshot wants a home directory
      Environment = [ "HOME=/run/matrix-hookshot" ];

      DynamicUser = true;
      StateDirectory = "matrix-hookshot";
      RuntimeDirectory = "matrix-hookshot";
      RuntimeDirectoryMode = "0700";

      RestrictNamespaces = true;
      PrivateUsers = true;
      ProtectHostname = true;
      ProtectClock = true;
      ProtectKernelTunables = true;
      ProtectKernelModules = true;
      ProtectKernelLogs = true;
      ProtectControlGroups = true;
      RestrictAddressFamilies = [ "AF_INET AF_INET6" ];
      LockPersonality = true;
      RestrictRealtime = true;
      ProtectProc = "invisible";
      ProcSubset = "pid";
      UMask = 77;
    };
  };

  services.matrix-hookshot = {
    enable = true;

    serviceDependencies = [
      "conduit.service"
    ];

    registrationFile = "/run/matrix-hookshot/registration.yaml";

    settings = {
      bridge = {
        inherit domain;
        url = "http://localhost:${toString conduitCfg.settings.global.port}";
        mediaUrl = conduitCfg.settings.global.well_known.client;
        port = 9993;
        bindAddress = "127.0.0.1";
      };

      bot.displayname = "Hookshot";

      generic = {
        enabled = true;
        outbound = false;
        # Only allow webhooks from localhost for the moment
        urlPrefix = "http://127.0.0.1:9000/webhook";
        userIdPrefix = "_webhooks_";
        allowJsTransformationFunctions = true;
      };

      encryption.storagePath = "/var/lib/matrix-hookshot/cryptostore";

      permissions = [
        {
          actor = "matrix.tlater.net";
          services = [
            {
              service = "*";
              level = "notifications";
            }
          ];
        }
        {
          actor = "@tlater:matrix.tlater.net";
          services = [
            {
              service = "*";
              level = "admin";
            }
          ];
        }
      ];

      listeners = [
        {
          port = 9000;
          resources = [
            "webhooks"
          ];
        }
        {
          port = 9001;
          resources = [
            "metrics"
          ];
        }
      ];

      metrics.enable = true;
    };
  };
}