{
  config,
  lib,
  namespace,
  ...
}:
let
  inherit (lib.${namespace}) mkOpt mkReverseProxyOpt;
  cfg = config.${namespace}.services.matrix;

  matrixConfig = {
    services.matrix-synapse = {
      enable = true;
      dataDir = cfg.dataDir;
      configureRedisLocally = true;
      enableRegistrationScript = true;
      settings = {
        server_name = "mjallen.dev";
        public_baseurl = "https://matrix.mjallen.dev";
        serve_server_wellknown = true;

        listeners = [
          {
            port = cfg.port;
            tls = false;
            x_forwarded = true;
            bind_addresses = [
              "::1"
              "0.0.0.0"
            ];
            resources = [
              {
                names = [
                  "client"
                  "federation"
                ];
                compress = false;
              }
            ];
          }
        ];

        oidc_providers = [
          {
            idp_id = "authentik";
            idp_name = "authentik";
            discover = true;
            issuer = "https://authentik.mjallen.dev/application/o/matrix/";
            client_id = "KiChwyQn2kMtXU6LU0x3dlCb0jO6VB6e9xsN9NPs"; # TO BE FILLED
            client_secret = "6XRfNCUayZqnyaMv0QSEeFz98x2y8BkXnDyylmvAbg71YkQVtpEybP6jmPzncpJsx4k5evtziicgu8p9dOa2oADHL6Ao13643VMTsI4BSel1sbIICA2TH755BpB9J39A"; # TO BE FILLED
            scopes = [
              "openid"
              "profile"
              "email"
            ];
            user_mapping_provider = {
              config = {
                localpart_template = "{{ user.preferred_username }}";
                display_name_template = "{{ user.preferred_username|capitalize }}"; # TO BE FILLED: If your users have names in Authentik and you want those in Synapse, this should be replaced with user.name|capitalize.
              };
            };
            allow_existing_users = true;
          }
        ];

        # Database configuration
        database = {
          name = "psycopg2";
          allow_unsafe_locale = true;
          args = {
            user = "synapse";
            database = "synapse";
            host = "localhost";
            cp_min = 5;
            cp_max = 10;
          };
        };

        # Registration settings
        enable_registration = false; # Set to true initially to create admin user
        enable_registration_without_verification = false;
        # registration_shared_secret = "BogieDudie1";

        # Media settings
        max_upload_size = "50M";
        media_store_path = "${cfg.dataDir}/media";

        # Logging
        # log_config = "/var/lib/matrix-synapse/log_config.yaml";
        trusted_key_servers = [
          {
            server_name = "matrix.org";
          }
        ];
      };
    };

    users.users.matrix-synapse = {
      isSystemUser = true;
      group = "matrix-synapse";
    };
    users.groups.matrix-synapse = { };

    services.postgresql = {
      enable = lib.mkDefault true;
      #authentication = lib.mkOverride 10 ''
      #  # TYPE  DATABASE        USER            ADDRESS                 METHOD
      #  local   all             all                                     peer
      #  host    all             all             127.0.0.1/32            trust
      #  host    all             all             ::1/128                 trust
      #'';
      ensureDatabases = [ "synapse" ];
      ensureUsers = [
        {
          name = "synapse";
          ensureDBOwnership = true;
        }
      ];
    };
  };

  # Create reverse proxy configuration using mkReverseProxy
  reverseProxyConfig = lib.${namespace}.mkReverseProxy {
    name = "matrix";
    subdomain = cfg.reverseProxy.subdomain;
    url = "http://${cfg.localAddress}:${toString cfg.port}";
    middlewares = cfg.reverseProxy.middlewares;
  };

  fullConfig = {
    ${namespace}.services.traefik = lib.mkIf cfg.reverseProxy.enable {
      reverseProxies = [ reverseProxyConfig ];
    };
  }
  // matrixConfig;
in
with lib;
{
  options.${namespace}.services.matrix = {
    enable = mkEnableOption "matrix service";

    port = mkOpt types.int 8008 "Port for matrix to be hosted on";

    localAddress = mkOpt types.str "127.0.0.1" "local address of the service";

    dataDir = mkOpt types.str "" "Path to the data dir";

    reverseProxy = mkReverseProxyOpt;
  };

  config = lib.mkIf cfg.enable fullConfig;
}
