{ config, ... }:

{
  sops.secrets = {
    ldap_synapse_passwd = {
      sopsFile = ../../secrets/neo.yaml;
    };

    neo_extra_config = {
      format = "yaml";
      sopsFile = ../../secrets/neo_extra_config.yaml;
      key = "";
    };

    matrix_appservice_irc_db = {
      sopsFile = ../../secrets/neo.yaml;
    };

    coturn_auth_secret = {
      sopsFile = ../../secrets/neo.yaml;
    };
  };

  networking.firewall = {
    allowedTCPPorts = [
      80
      443
      8008
      8448
    ];
  };

  services.matrix-synapse = {
    enable = true;

    plugins = with config.services.matrix-synapse.package.plugins; [
      matrix-synapse-ldap3
    ];

    settings = {
      server_name = "crans.org";

      report_stats = false;

      listeners = [
        {
          port = 8008;
          tls = false;
          bind_addresses = [
            "::"
            "0.0.0.0"
          ];
          type = "http";
          x_forwarded = true;
          resources = [
            {
              names = [ "client" ];
              compress = true;
            }
            {
              names = [ "federation" ];
              compress = false;
            }
          ];
        }
      ];

      database = {
        name = "psycopg2";
        args = {
          user = "synapse";
          database = "synapse";
          # Password is declared in extra config
          host = "172.16.10.1";
          cp_min = 5;
          cp_max = 10;
        };
      };

      modules = [
        {
          module = "ldap_auth_provider.LdapAuthProviderModule";
          config = {
            enabled = true;
            uri = "ldap://172.16.10.157:389";
            start_tls = false;
            base = "dc=crans,dc=org";
            attributes = {
              uid = "uid";
              mail = "mail";
              name = "sn";
            };
            binddn = "cn=synapse,ou=service-users,dc=crans,dc=org";
            bind_password_file = config.sops.secrets.ldap_synapse_passwd.path;
            filter = "(&(objectclass=inetOrgPerson)(objectclass=posixAccount))";
          };
        }
      ];

      turn_uris = [
        "turn:${config.services.coturn.realm}:3478?transport=udp"
        "turn:${config.services.coturn.realm}:3478?transport=tcp"
      ];
      turn_shared_secret = config.sops.secrets.coturn_auth_secret.path;
      turn_user_lifetime = "1h";

      app_service_config_files = [
        "/var/lib/matrix-appservice-irc/registration.yml"
      ];
    };

    extraConfigFiles = [
      config.sops.secrets.neo_extra_config.path
    ];
  };

  services.matrix-appservice-irc = {
    enable = true;

    registrationUrl = "http://localhost:9999";
    settings = {
      homeserver = {
        url = "https://matrix.crans.org:443";
        domain = "crans.org";

        dropMatrixMessagesAfterSecs = 3000;
        enablePresence = true;
      };

      database = {
        engine = "postgres";
        connectionString = config.sops.secrets.matrix_appservice_irc_db.path;
      };

      ircService = {
        servers = {
          "irc.crans.org" = {
            name = "Crans";
            onlyAdditionalAddresses = false;
            networkId = "crans";
            port = 6697;
            ssl = true;
            sslselfsign = true;
            sasl = false;
            allowExpiredCerts = false;
            sendConnectionMessages = true;
            passwordEncryptionKeyPath = "/var/lib/matrix-appservice-irc/passkey.pem";

            modePowerMap = {
              o = 50;
              v = 1;
            };

            dynamicChannels = {
              enabled = true;
              useHomeserverDirectory = true;
              aliasTemplate = "$CHANNEL";
            };

            membershipLists = {
              enabled = true;
              floodDelayMs = 100;
              global = {
                ircToMatrix = {
                  initial = true;
                  incremental = true;
                  requireMatrixJoined = true;
                };
                matrixToIrc = {
                  initial = true;
                  incremental = true;
                };
              };

              ignoreIdleUsersOnStartup = {
                enabled = true;
                idleForHours = 720;
              };
            };

            matrixClients = {
              userTemplate = "@irc_$NICK";
              idisplayName = "$NICK";
            };

            ircClients = {
              nickTemplate = "$DISPLAY";
              allowNickChanges = true;
              maxClients = 300;
              ipv6.enabled = false;
              idleTimeout = 10800;
              realnameFormat = "mxid";
              kickOn = {
                channelJoinFailure = true;
                ircConnectionFailure = true;
                userQuit = true;
              };
            };
          };
        };

        bridgeInfoState = {
          enabled = false;
        };

        logging = {
          level = "info";
          logging = "debug.log";
          errfile = "error.log";
          toConsole = true;
          maxFiles = 2;
        };

        metrics = {
          enabled = false;
        };

        matrixHandler = {
          eventCacheSize = 4096;
          shortReplyTemplate = "$NICK: $REPLY";
          longReplyTemplate = "<$NICK> \"$ORIGINAL\" <- $REPLY";
          shortReplyTresholdSeconds = 300;
        };
      };

      advanced = {
        maxHttpSockets = 1000;
        maxTxnSize = 10000000;
      };
    };
  };
}