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

{
  security.acme.email = "anish+acme@lakhwara.com";
  security.acme.acceptTerms = true;
  services.matrix-synapse = {
    enable = true;
    app_service_config_files = [
      #  # The registration file is automatically generated after starting the appservice for the first time.
      #  # cp /var/lib/matrix-appservice-discord/discord-registration.yaml /var/lib/matrix-synapse/
      #  # chown matrix-synapse:matrix-synapse /var/lib/matrix-synapse/discord-registration.yaml
      "/var/lib/matrix-synapse/discord-registration.yaml"
      "/var/lib/matrix-synapse/telegram-registration.yaml"
      #"/var/lib/matrix-synapse/slack-registration.yaml"
      #"/var/lib/matrix-synapse/whatsapp-registration.yaml"
    ];
    server_name = "sealight.xyz";
    registration_shared_secret = "hD9HQGTTDxp0mQsQ5JDsfudWMDiubmZENOgPchIvfBvUlPxlvQSvjoO4wn2L1seU";
    enable_metrics = true;
    enable_registration = true;
    database_type = "psycopg2";
    database_args = {
      database = "matrix-synapse";
    };
    listeners = [
      {
        port = 8448;
        tls = false;
        resources = [{
          compress = true;
          names = [ "client" "federation" ];
        }];
      }
      {
        port = 9090;
        type = "metrics";
        bind_address = "0.0.0.0";
        resources = [{
          compress = false;
          names = [ ];
        }];
        tls = false;
      }
    ];
    extraConfig = ''
      max_upload_size: "50M"
      use_presence: false
    '';
    ## coturn based TURN server integration (TURN server setup mentioned later),
    ## shared secret generated while configuring coturn
    ## and reused here (power of Nix being a real programming language)
    turn_uris = [
      "turn:turn.sealight.xyz:3478?transport=udp"
      "turn:turn.sealight.xyz:3478?transport=tcp"
    ];
    turn_shared_secret = config.services.coturn.static-auth-secret;
  };

  services.coturn = {
    enable = true;
    use-auth-secret = true;
    static-auth-secret = "jXW1ohIq6wM3NB00xeME3uBihY85xjpkhGoyzBIdwhOpj7gjyxXZu1fwp1lUiYwJ";
    realm = "turn.sealight.xyz";
    min-port = 49111;
    max-port = 51111;
    no-cli = true;
    no-tcp-relay = true;
    no-tls = true;
    cert = "${config.security.acme.certs."turn.sealight.xyz".directory}/full.pem";
    pkey = "${config.security.acme.certs."turn.sealight.xyz".directory}/key.pem";
    extraConfig = ''
      verbose
      user-quota=12
      total-quota=1200
      denied-peer-ip=10.0.0.0-10.255.255.255
      denied-peer-ip=192.168.0.0-192.168.255.255
      denied-peer-ip=172.16.0.0-172.31.255.255
      denied-peer-ip=0.0.0.0-0.255.255.255
      denied-peer-ip=100.64.0.0-100.127.255.255
      denied-peer-ip=127.0.0.0-127.255.255.255
      denied-peer-ip=169.254.0.0-169.254.255.255
      denied-peer-ip=192.0.0.0-192.0.0.255
      denied-peer-ip=192.0.2.0-192.0.2.255
      denied-peer-ip=192.88.99.0-192.88.99.255
      denied-peer-ip=198.18.0.0-198.19.255.255
      denied-peer-ip=198.51.100.0-198.51.100.255
      denied-peer-ip=203.0.113.0-203.0.113.255
      denied-peer-ip=240.0.0.0-255.255.255.255
    '';
  };

  security.acme.certs.${config.services.coturn.realm} = {
    /* insert here the right configuration to obtain a certificate */
    webroot = "/var/lib/acme/acme-challenge/";
    email = "anish+acme@lakhwara.com";
    postRun = "systemctl restart coturn.service";
    group = "turnserver";
  };

  # TODO fix up jitsi bridge stuff
  ## services.jitsi-meet = {
  ##   enable = true;
  ##   hostName = "jitsi.sealight.xyz";
  ## };
  ## services.jitsi-videobridge.enable = true;

  services.mautrix-telegram = {
    enable = true;
    environmentFile = /etc/secrets/telegram.env; # file containing the appservice and telegram tokens
    # The appservice is pre-configured to use SQLite by default. It's also possible to use PostgreSQL.
    settings = {
      homeserver = {
        address = "https://sealight.xyz";
        domain = "sealight.xyz";
      };
      appservice = {
        provisioning.enabled = false;
        id = "telegram";
        bot_username = "telegrambridge";
        public = {
          enabled = false;
          prefix = "/public";
          external = "https://chat.sealight.xyz/public";
        };
        address = "http://localhost:18787";
        port = 18787;
        # The service uses SQLite by default, but it's also possible to use PostgreSQL instead:
        #database = "postgresql:///mautrix-telegram?host=/run/postgresql";
      };
      bridge = {
        relaybot.authless_portals = false;
        permissions = {
          "@aynish:sealight.xyz" = "admin";
        };
      };
    };
  };

  services.mx-puppet-discord = {
    enable = true;
    settings = {
      bridge = {
        bindAddress = "localhost";
        port = 16785;
        domain = "sealight.xyz";
        homeserverUrl = "https://sealight.xyz";
        avatarUrl = "https://discord.com/assets/2d20a45d79110dc5bf947137e9d99b66.svg";
      };
      provisioning = {
        whitelist = [ "@aynish:sealight.xyz" ];
      };
      relay = {
        whitelist = [ "@aynish:sealight.xyz" ];
      };
      namePatterns = {
        group = ":name";
        room = ":name";
        user = ":name (Discord)";
        userOverride = ":displayname";
      };
      presence = {
        enabled = false;
      };
    };
    serviceDependencies = [ "matrix-synapse.service" ];
  };

  services.heisenbridge = {
    enable = true;
    homeserver = "https://sealight.xyz";
    listenPort = 14456;
    appServiceToken = "wyujLh8kjpmk2bfKeEE3sZ2gWOEUBKK5";
    homeserverToken = "yEHs7lthD2ZHUibJOAv1APaFhEjxN5PT";
  };

  services.postgresql = {
    enable = true;
    ## postgresql user and db name remains in the
    ## service.matrix-synapse.database_args setting which
    ## by default is matrix-synapse
    # TODO agenix
    initialScript = pkgs.writeText "synapse-init.sql" ''
      CREATE ROLE "matrix-synapse" WITH LOGIN PASSWORD "Da0?H*9i{x?,]|'kq@iBwlIzu"; 
      CREATE DATABASE "matrix-synapse" WITH OWNER "matrix-synapse"
          TEMPLATE template0
          LC_COLLATE = "C"
          LC_CTYPE = "C";
    '';
  };

  networking.firewall =
    let
      range = with config.services.coturn; [{
        from = min-port;
        to = max-port;
      }];
    in
    {
      enable = true;
      allowedUDPPortRanges = range; # coturn
      allowedTCPPortRanges = range;
      allowedTCPPorts = [
        22 # SSH
        8448 # Matrix federation
        8008
        80
        443
        3478 # Coturn service
        5349 # Coturn service
        9090 # Synapse Metrics
      ];
      allowedUDPPorts = [
        3478
        5349 # Coturn service
      ];
    };

  nixpkgs.overlays = [
    (self: super: {
      element-web = super.element-web.override {
        conf = {
          default_server_config = {
            "m.homeserver" = {
              "base_url" = "https://chat.sealight.xyz";
              "server_name" = "sealight.xyz";
            };
            "m.identity_server" = {
              "base_url" = "https://vector.im";
            };
          };

          ## jitsi will be setup later,
          ## but we need to add to Riot configuration
          jitsi.preferredDomain = "jitsi.sealight.xyz";
        };
      };
    })
  ];

  services.nginx = {
    enable = true;
    virtualHosts = {
      "sealight.xyz" = {
        #forceSSL = true;
        #enableACME = true;
        locations."/" = {
          root = "/var/www/sealight.xyz";
        };
        locations."/_matrix" = {
          proxyPass = "http://localhost:8448";
        };
        locations."/slackbridge" = {
          proxyPass = "http://localhost:9899";
        };
      };
      ## virtual host for Synapse
      "chat.sealight.xyz" = {
        #forceSSL = true;
        #enableACME = true; # TODO
        #useACMEHost = "sealight.xyz"; # TODO
        locations."/" = {
          proxyPass = "http://localhost:8448";
        };
      };
      ## virtual host for Riot/Web
      "element.sealight.xyz" = {
        #forceSSL = true;
        #enableACME = true; # TODO
        #useACMEHost = "sealight.xyz"; # TODO
        ## root points to the riot-web package content, also configured via Nix
        locations."/" = {
          root = pkgs.element-web;
        };
      };
      ${config.services.jitsi-meet.hostName} = {
        #enableACME = true; # TODO
        #forceSSL = true; # TODO
      };
    };
    ## other nginx specific best practices
    recommendedGzipSettings = true;
    recommendedOptimisation = true;
    recommendedTlsSettings = true;
  };

  # environment.systemPackages = with pkgs; [ matrix-appservice-slack ];
  #services.mx-puppet-slack= {
  #enable = false;
  #settings = {
  #  bridge = { 
  #    bindAddress = "localhost";
  #    port = 16786;
  #    domain = "sealight.xyz";
  #    homeserverUrl = "https://sealight.xyz";
  #  };
  #  provisioning = {
  #    whitelist = [ "@aynish:sealight.xyz" ];
  #  };
  #  relay = {
  #    whitelist = [ "@aynish:sealight.xyz" ];
  #  };
  #  namePatterns = {
  #    group = ":name";
  #    room = ":name[:team? - :team,]";
  #    user = ":name (Slack)";
  #    userOverride = ":displayname";
  #  };
  #  presence = {
  #    enabled = false;
  #  };
  #  oauth = {
  #    enabled = false;
  #  };
  #};
  #serviceDependencies = ["matrix-synapse.service"];
  #};

  # services.mautrix-whatsapp = {
  #   enable = false;
  # The appservice is pre-configured to use SQLite by default. It's also possible to use PostgreSQL.
  #configOptions = {
  #  homeserver = {
  #    address = "https://chat.sealight.xyz";
  #    domain = "sealight.xyz";
  #  };
  #  appservice = {
  #    id = "whatsapp";
  #    address = http://localhost:9897;
  #    hostname = "0.0.0.0";
  #    port = 9897;
  #    database = {
  #      type = "sqlite3";
  #      uri = "/var/lib/mautrix-whatsapp/mautrix-whatsapp.db";
  #    };
  #    state_store_path = "/var/lib/mautrix-whatsapp/mx-state.json";
  #    bot = {
  #      username = "whatsappbot";
  #      displayname = "WhatsApp bridge bot";
  #      avatar = "mxc://maunium.net/NeXNQarUbrlYBiPCpprYsRqr";
  #    };
  #    as_token = "";
  #    hs_token = "";
  #  };
  #  bridge = {
  #    username_template = "whatsapp_{{.}}";
  #    displayname_template = "{{if .Notify}}{{.Notify}}{{else}}{{.Jid}}{{end}} (WA)";
  #    command_prefix = "!wa";
  #    permissions = {
  #      "@aynish:sealight.xyz" = 100;
  #    };
  #  };
  #  logging = {
  #    directory = "/var/lib/mautrix-whatsapp/logs";
  #    file_name_format = "{{.Date}}-{{.Index}}.log";
  #    file_date_format = "\"2006-01-02\"";
  #    file_mode = 384;
  #    timestamp_format = "Jan _2, 2006 15:04:05";
  #    print_level = "debug";
  #  };
  #  metrics = {
  #    enabled = true;
  #    listen  = "http://localhost:5070";
  #  };
  #};
  # };


}
