{ config, pkgs, ... }:

let
  rootDomain = config.networking.domain;
  ports = import ./Ports.nix;
in
{
  imports = [  ./Gmnisrv.nix ];
  networking.firewall = {
    allowedTCPPorts = [
      ports.ssh
      ports.git
      ports.http
      ports.https
      ports.sabten
      ports.gemini
      ports.radicale
      ports.znc
    ];
  };

  services = {

    libreddit = {
      enable = true;
      address = "127.0.0.1";
      openFirewall = true;
      port = ports.libreddit;
    };

    invidious = {
      enable = true;
      database.createLocally = true;
      domain = "youtube.${rootDomain}";
      nginx.enable = false; # do this myself, below
      port = ports.invidious;
    };

    radicale = {
      enable = true;
      settings = {
        server = {
          hosts = [
            "0.0.0.0:${toString ports.radicale}"
            "[::]:${toString ports.radicale}"
          ];
        };
        auth = {
          type = "htpasswd";
          htpasswd_filename = "/etc/radicale/users";
          htpasswd_encryption = "plain";
        };
      };
    };
    gmnisrv = {
      enable = true;
      listen = "0.0.0.0:${toString ports.gemini} [::]:${toString ports.gemini}";
      settings = {
        ":tls" = { store = "/var/lib/gmnisrv"; };
        "bsima.me" = {
          "root" = "/var/web/ben";
        };
        "${rootDomain}" = {
          "root" = "/var/web/simatime.com";
          "cgi" = "on";
        };
      };
    };

    nginx = {
      enable = true;
      recommendedGzipSettings = true;
      recommendedOptimisation = true;
      recommendedProxySettings = true;
      recommendedTlsSettings = true;
      statusPage = true;

      user = "nginx";
      group = "nginx";

      virtualHosts = {
        ${rootDomain} = {
          forceSSL = true;
          enableACME = true;
          locations = {
            # the nginx/cgit module puts a '/' at the end of 'location', so we need to
            # redirect '/git' to '/git/'
            "/git".return = "301 https://$host/git/";
            # disabled for nixpert test
            #"/" = {
            #  root = "/var/web/simatime.com";
            #  extraConfig = ''
            #    autoindex on;
            #  '';
            #};
            # serve /~$USER paths
            "~ ^/~(.+?)(/.*)?$" = {
              alias = "/var/web/$1$2";
              index = "index.html index.htm";
              extraConfig = ''
                autoindex on;
              '';
            };
          };
        };

        "bsima.me" = {
          locations."/" = {
            root = "/var/web/ben";
            index = "index.html index.htm";
            extraConfig = ''
              autoindex on;
            '';
          };
          serverAliases = [ "www.bsima.me" ];
          forceSSL = true;
          useACMEHost = rootDomain;
        };

        "hoogle.${rootDomain}" = {
          locations."/".proxyPass = "http://${ports.bensIp}:${toString ports.hoogle}";
          forceSSL = true;
          useACMEHost = rootDomain;
        };

        "tv.${rootDomain}" = {
          locations."/".proxyPass = "http://${ports.bensIp}:${toString ports.jellyfin}";
          forceSSL = true;
          useACMEHost = rootDomain;
        };

        "cal.${rootDomain}" = {
          locations."/".proxyPass = "http://localhost:${toString ports.radicale}";
          forceSSL = true;
          useACMEHost = rootDomain;
        };

        "reddit.${rootDomain}" = {
          locations."/".proxyPass = "http://localhost:${toString ports.libreddit}";
          forceSSL = true;
          useACMEHost = rootDomain;
        };
        "www.reddit.${rootDomain}" = {
          forceSSL = true;
          useACMEHost = rootDomain;
          globalRedirect = "reddit.${rootDomain}";
        };
        "old.reddit.${rootDomain}" = {
          forceSSL = true;
          useACMEHost = rootDomain;
          globalRedirect = "reddit.${rootDomain}";
        };

        "youtube.${rootDomain}" = {
          locations."/".proxyPass = "http://localhost:${toString ports.invidious}";
          forceSSL = true;
          useACMEHost = rootDomain;
        };
        "www.youtube.${rootDomain}" = {
          forceSSL = true;
          useACMEHost = rootDomain;
          globalRedirect = "youtube.${rootDomain}";
        };

        "devalloc.io" = {
          forceSSL = true;
          useACMEHost = rootDomain;
          globalRedirect = "dragons.dev";
        };

        "dragons.dev" = {
          locations."/".proxyPass = "http://${ports.bensIp}:${toString ports.dragons}";
          forceSSL = true;
          useACMEHost = rootDomain;
        };

        "dandel-rovbur.${rootDomain}" = {
          locations."/".proxyPass = "http://${ports.bensIp}:${toString ports.dandel-rovbur}";
          forceSSL = true;
          useACMEHost = rootDomain;
        };

        "sabten.${rootDomain}" = {
          locations."/".proxyPass = "http://localhost:${toString ports.sabten}";
          forceSSL = true;
          useACMEHost = rootDomain;
        };

        "sd.${rootDomain}" = {
          forceSSL = true;
          useACMEHost = rootDomain;
          locations."/" = {
            proxyPass = "http://${ports.bensIp}:${toString ports.stableDiffusion}";
            proxyWebsockets = true;
          };
        };

        "notebook.${rootDomain}" = {
          forceSSL = true;
          useACMEHost = rootDomain;
          locations = {
            "/" = {
              proxyPass = "http://${ports.bensIp}:${toString ports.jupyter}";
              proxyWebsockets = true;
              extraConfig = ''
                proxy_buffering off;
                proxy_read_timeout 86400;
              '';
            };
            "/(api/kernels/[^/]+/channels|terminals/websocket)/" = {
              proxyPass = "http://${ports.bensIp}:${toString ports.jupyter}";
              proxyWebsockets = true;
            };
          };
        };

      };
    };
  };

  # This must contain all of the other domains we host
  security.acme.certs.${rootDomain}.extraDomainNames = [
    "bsima.me" "www.bsima.me"
    "dragons.dev" "devalloc.io"
    "nixpert.chat"
  ] ++ map (sub: "${sub}.${rootDomain}") [
    "tv"
    "matrix"
    "chat"
    "hoogle"
    "dandel-rovbur"
    "sabten"
    "cal"
    "notebook"
    "reddit"
    "old.reddit"
    "www.reddit"
    "youtube"
    "www.youtube"
  ];
}