{
  config,
  lib,
  pkgs,
  ...
}:

let
  cfg = config.services.matrix-synapse;

  mkMautrixBridgeOptions = name: pkgName: {
    enable = mkEnableOption "Mautrix-${name} for your Matrix-Synapse instance.";
    package = mkPackageOption pkgs pkgName { };
    admin = mkOption {
      type = types.str;
      description = "The user to give admin permissions to.";
      example = "@admin:example.com";
    };
  };

  mkMautrixBridge = name: port: {
    environment.systemPackages = [ cfg.bridges.${name}.package ];

    services."mautrix-${name}" = {
      enable = true;
      package = cfg.bridges.${name}.package;
      environmentFile = mkIf cfg.sops config.sops.templates."mautrix-${name}/env-file".path;
      settings = {
        bridge = {
          permissions = {
            "*" = "relay";
            "${cfg.settings.server_name}" = "user";
            "${cfg.bridges.${name}.admin}" = "admin";
          };
        };
        homeserver = {
          address = "http://localhost:${toString cfg.port}";
          domain = cfg.settings.server_name;
        };
        appservice = {
          address = "http://localhost:${toString port}";
          public_address = cfg.settings.public_baseurl;
          hostname = "localhost";
          inherit port;
        };
        provisioning.shared_secret = "$MAUTRIX_${toUpper name}_PROVISIONING_SHARED_SECRET";
        public_media = {
          enabled = false;
          signing_key = "$MAUTRIX_${toUpper name}_PUBLIC_MEDIA_SIGNING_KEY";
        };
        direct_media = {
          enabled = false;
          server_key = "$MAUTRIX_${toUpper name}_DIRECT_MEDIA_SERVER_KEY";
        };
        backfill = {
          enabled = true;
        };
        encryption = {
          allow = true;
          default = true;
          require = false;
          pickle_key = "$MAUTRIX_${toUpper name}_ENCRYPTION_PICKLE_KEY";
        };
      };
    };

    sops = mkIf cfg.sops (
      let
        owner = "mautrix-${name}";
        group = "mautrix-${name}";
        mode = "0400";
      in
      {
        secrets."mautrix-${name}/encryption-pickle-key" = {
          inherit owner group mode;
        };
        secrets."mautrix-${name}/provisioning-shared-secret" = {
          inherit owner group mode;
        };
        secrets."mautrix-${name}/public-media-signing-key" = {
          inherit owner group mode;
        };
        secrets."mautrix-${name}/direct-media-server-key" = {
          inherit owner group mode;
        };
        templates."mautrix-${name}/env-file" = {
          inherit owner group mode;
          content = ''
            MAUTRIX_${toUpper name}_ENCRYPTION_PICKLE_KEY=${
              config.sops.placeholder."mautrix-${name}/encryption-pickle-key"
            }
            MAUTRIX_${toUpper name}_PROVISIONING_SHARED_SECRET=${
              config.sops.placeholder."mautrix-${name}/provisioning-shared-secret"
            }
            MAUTRIX_${toUpper name}_PUBLIC_MEDIA_SIGNING_KEY=${
              config.sops.placeholder."mautrix-${name}/public-media-signing-key"
            }
            MAUTRIX_${toUpper name}_DIRECT_MEDIA_SERVER_KEY=${
              config.sops.placeholder."mautrix-${name}/direct-media-server-key"
            }
          '';
        };
      }
    );

  };

  inherit (lib)
    mkEnableOption
    mkIf
    mkMerge
    mkOption
    mkPackageOption
    toUpper
    types
    ;

  inherit (builtins) toString;
in
{
  options.services.matrix-synapse = {
    bridges = {
      whatsapp = mkMautrixBridgeOptions "WhatsApp" "mautrix-whatsapp";
      signal = mkMautrixBridgeOptions "Signal" "mautrix-signal";
    };
  };

  config = mkMerge [
    (mkIf cfg.bridges.whatsapp.enable (mkMautrixBridge "whatsapp" 29318))
    (mkIf cfg.bridges.whatsapp.enable {
      services.mautrix-whatsapp = {
        settings = {
          network = {
            displayname_template = "{{or .BusinessName .PushName .Phone}} (WA)";
            history_sync.request_full_sync = true;
          };
        };
      };
    })
    (mkIf cfg.bridges.signal.enable (mkMautrixBridge "signal" 29328))
    (mkIf cfg.bridges.signal.enable {
      services.mautrix-signal = {
        settings = {
          network = {
            displayname_template = "{{or .ProfileName .PhoneNumber \"Unknown user\" }} (S)";
          };
        };
      };
    })
  ];
}
