{
  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
    # TODO(tlater): Enable when
    # https://github.com/matrix-org/matrix-hookshot/issues/1060 is
    # fixed
    # extraSettings = {
    #   "de.sorunome.msc2409.push_ephemeral" = true;
    #   push_ephemeral = true;
    #   "org.matrix.msc3202" = true;
    # };

    runtimeRegistration = "${cfg.registrationFile}";
  };
in
{
  # users = {
  #   users.matrix-hookshot = {
  #     home = "/run/matrix-hookshot";
  #     group = "matrix-hookshot";
  #     isSystemUser = true;
  #   };

  #   groups.matrix-hookshot = { };
  # };

  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" ];

      # User = "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_UNIX"
        "AF_INET"
        "AF_INET6"
      ];
      LockPersonality = true;
      RestrictRealtime = true;
      ProtectProc = "invisible";
      ProcSubset = "pid";
      UMask = 77;
    };
  };

  # services.redis.servers.matrix-hookshot = {
  #   enable = true;
  #   user = "matrix-hookshot";
  # };

  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";

      # cache.redisUri = "redis://${config.services.redis.servers.matrix-hookshot.unixSocket}";

      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;
      };

      # TODO(tlater): Enable when
      # https://github.com/matrix-org/matrix-hookshot/issues/1060 is
      # fixed
      # 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.enabled = true;
    };
  };
}