{
  lib,
  config,
  pkgs,
  ...
}:
let
  inherit (config.networking) domain;
  inherit (config.serverConfig) vhosts;

  fqdn = vhosts.matrix_host.host;
  base_url = "https://${fqdn}";

  clientConfig."m.homeserver" = {inherit base_url; }; # = "https://${vhosts.matrix_host.host}";
  serverConfig."m.server" = "${vhosts.matrix_host.host}:443";
  mkWellKnown = data: ''
    default_type application/json;
    add_header Access-Control-Allow-Origin *;
    return 200 '${builtins.toJSON data}';
  '';
  synapse_backend = "http://[::1]:8008";
in
{
  services.postgresql = {
    enable = true;
    ensureDatabases = [ "synapse" ];
    ensureUsers = [
      {
        name = "synapse";
        passFile = config.age.secrets.synapse_db_pass.path;
        ensureDBOwnership = true;
      }
    ];
  };

  
  services.matrix-synapse = {
    enable = true;
    settings.server_name = domain;
    # The public base URL value must match the `base_url` value set in `clientConfig` above.
    # The default value here is based on `server_name`, so if your `server_name` is different
    # from the value of `fqdn` above, you will likely run into some mismatched domain names
    # in client applications.
    settings.public_baseurl = base_url;
    settings.listeners = [
      { port = 8008;
        bind_addresses = [ "::1" ];
        type = "http";
        tls = false;
        x_forwarded = true;
        resources = [ {
          names = [ "client" "federation" ];
          compress = true;
        } ];
      }
    ];

    settings.database = {
      name = "psycopg2";
      args = { user="synapse"; database= "synapse"; };
    };
    settings.log_config = ./matrix_synapse_log_config.yaml;
    settings.enable_registration = false;
    configureRedisLocally = true;
    settings.redis.enabled = true;

    settings.app_service_config_files = [
      # The registration file is automatically generated after starting the
      # appservice for the first time.
      # cp /var/lib/mautrix-telegram/telegram-registration.yaml \
      #   /var/lib/matrix-synapse/
      # chown matrix-synapse:matrix-synapse \
      #   /var/lib/matrix-synapse/telegram-registration.yaml
      # "/var/lib/matrix-synapse/discord-registration.yaml"
    ];
  };

#  services.matrix-synapse-next = {
#    enable = true;
#
#    workers.federationSenders = 1;
#    workers.federationReceivers = 1;
#    workers.initialSyncers = 1;
#    workers.normalSyncers = 1;
#    workers.eventPersisters = 2;
#    workers.useUserDirectoryWorker = true;
#    mainLogConfig = ./matrix_synapse_log_config.yaml;
#
#    enableNginx = true;
#    enableSlidingSync = false;
#
#    settings = {
#      suppress_key_server_warning = true;
#      server_name = domain;
#      public_baseurl = "https://${domain}";
#      enable_registration = true;
#      registration_requires_token = true;
#      registration_shared_secret_path = config.age.secrets.synapse_registration_shared_secret.path;
#      # enable_registration_without_verification = true;
#      # mainLogConfig = ./matrix_synapse_log_config.yaml;
#
#      # registrations_require_3pid = [ "email" ];
#
#      database = {
#        name = "psycopg2";
#        args = {
#          host = "localhost";
#          port = config.services.postgresql.settings.port;
#          dbname = "synapse";
#          user = "synapse";
#          cp_min = 5;
#          cp_max = 10;
#          client_encoding = "auto";
#          passfile = config.age.secrets.synapse_db_pass_prepared.path;
#        };
#      };
#    };
#  };
  services.redis.servers."".enable = true;

  age.secrets.synapse_db_pass = {
    file = ../secrets/synapse_db_pass.age;
    owner = "postgres";
    group = "postgres";
  };
  age.secrets.synapse_db_pass_prepared = {
    file = ../secrets/synapse_db_pass_prepared.age;
    owner = "matrix-synapse";
    group = "matrix-synapse";
    mode = "0600";
  };
  age.secrets.synapse_registration_shared_secret = {
    file = ../secrets/synapse_registration_shared_secret.age;
    owner = "matrix-synapse";
    group = "matrix-synapse";
    mode = "0600";
  };

  environment.systemPackages = with pkgs; [
    matrix-synapse-tools.synadm
    matrix-synapse
  ];


    services.nginx = {
      enable = true;
      recommendedTlsSettings = true;
      recommendedOptimisation = true;
      recommendedGzipSettings = true;
      recommendedProxySettings = true;

      virtualHosts."${domain}" = {
        enableACME = true;
        forceSSL = true;
        # This section is not needed if the server_name of matrix-synapse is equal to
        # the domain (i.e. example.org from @foo:example.org) and the federation port
        # is 8448.
        # Further reference can be found in the docs about delegation under
        # https://element-hq.github.io/synapse/latest/delegate.html
        locations."= /.well-known/matrix/server".extraConfig = mkWellKnown serverConfig;
        # This is usually needed for homeserver discovery (from e.g. other Matrix clients).
        # Further reference can be found in the upstream docs at
        # https://spec.matrix.org/latest/client-server-api/#getwell-knownmatrixclient
        locations."= /.well-known/matrix/client".extraConfig = mkWellKnown clientConfig;
      };

      virtualHosts."${fqdn}" = {
        enableACME = true;
        forceSSL = true;

        locations."/_matrix" = {
          proxyPass = synapse_backend;
          #extraConfig = ''
          #  add_header X-debug-backend ${synapse_backend};
          #  add_header X-debug-group $synapse_uri_group;
          #  client_max_body_size ${config.services.matrix-synapse-next.settings.max_upload_size};
          #  proxy_read_timeout 10m;
          #'';
        };
        locations."/_synapse/client".proxyPass = synapse_backend;
      };    
    };

#  services.nginx = {
#    enable = true;
#    virtualHosts."${domain}" = {
#      forceSSL = true;
#      enableACME = lib.mkForce false; # use the cert above, not some weird one that matrix-synapse module supplies
#      useACMEHost = domain;
#      locations."/.well-known/matrix/server" = {
#        return = "200 '{\"m.server\":\"${vhosts.matrix_host.host}:443\"}'";
#        extraConfig = ''
#          default_type application/json;
#          add_header Access-Control-Allow-Origin *;
#          add_header Accept-Ranges bytes;'';
#      };
#      locations."/.well-known/matrix/client" = {
#        return = "200 '{\"m.homeserver\": {\"base_url\": \"https://${vhosts.matrix_host.host}\"}}'";
#        extraConfig = ''
#          add_header Access-Control-Allow-Origin *;
#          default_type application/json;
#        '';
#      };
#      locations."/_matrix" = {
#        proxyPass = "http://$synapse_backend";
#        extraConfig = ''
#          add_header X-debug-backend $synapse_backend;
#          add_header X-debug-group $synapse_uri_group;
#          client_max_body_size ${config.services.matrix-synapse-next.settings.max_upload_size};
#          proxy_read_timeout 10m;
#        '';
#      };
#      locations."/_synapse/client" = {
#        proxyPass = "http://$synapse_backend";
#      };
#      locations."~ ^/_matrix/client/(r0|v3)/sync$" = {
#        proxyPass = "http://$synapse_backend";
#        extraConfig = ''
#          proxy_read_timeout 1h;
#        '';
#      };
#      locations."~ ^/_matrix/client/(api/v1|r0|v3)/initialSync$" = {
#        proxyPass = "http://synapse_worker_initial_sync";
#        extraConfig = ''
#          proxy_read_timeout 1h;
#        '';
#      };
#      locations."~ ^/_matrix/client/(api/v1|r0|v3)/rooms/[^/]+/initialSync$" = {
#        proxyPass = "http://synapse_worker_initial_sync";
#        extraConfig = ''
#          proxy_read_timeout 1h;
#        '';
#      };
#      #      locations."/.well-known/matrix" = {
#        proxyPass = "http://$synapse_backend";
#      };
#    };
#  };
  #  networking.firewall.allowedTCPPorts = [ 8448 8008 ];
}