self:
{ config, lib, ... }:

let
  cfg = config.services.jetpham-website;
  package = self.packages.x86_64-linux.default;
  qaApi = self.packages.x86_64-linux.qa-api;
  webhookSecretPath =
    if cfg.webhookSecretFile != null then
      cfg.webhookSecretFile
    else
      config.age.secrets.webhook-secret.path;
in
{
  options.services.jetpham-website = {
    enable = lib.mkEnableOption "Jet Pham's personal website";

    domain = lib.mkOption {
      type = lib.types.str;
      default = "jetpham.com";
      description = "Domain to serve the website on.";
    };

    tor.enable = lib.mkEnableOption "Tor hidden service for the website";

    qaNotifyEmail = lib.mkOption {
      type = lib.types.str;
      default = "jet@extremist.software";
      description = "Email address to receive Q&A notifications.";
    };

    qaMailDomain = lib.mkOption {
      type = lib.types.str;
      default = "extremist.software";
      description = "Mail domain for Q&A reply addresses.";
    };

    qaReplyDomain = lib.mkOption {
      type = lib.types.str;
      default = "extremist.software";
      description = "Domain used in the static Q&A Reply-To address (`qa@...`). Use a dedicated subdomain and route only that mail into the webhook to avoid impacting your main inbox if the Q&A API fails.";
    };

    webhookSecretFile = lib.mkOption {
      type = lib.types.nullOr lib.types.path;
      default = null;
      description = "File containing the WEBHOOK_SECRET for MTA Hook authentication.";
    };
  };

  config = lib.mkIf cfg.enable {
    age.secrets.webhook-secret = lib.mkIf (cfg.webhookSecretFile == null) {
      file = "${self}/secrets/webhook-secret.age";
      mode = "0400";
    };

    age.secrets.tor-onion-secret-key = lib.mkIf cfg.tor.enable {
      file = "${self}/secrets/tor-onion-secret-key.age";
      owner = "tor";
      group = "tor";
      mode = "0400";
    };
    age.secrets.tor-onion-public-key = lib.mkIf cfg.tor.enable {
      file = "${self}/secrets/tor-onion-public-key.age";
      owner = "tor";
      group = "tor";
      mode = "0444";
    };
    age.secrets.tor-onion-hostname = lib.mkIf cfg.tor.enable {
      file = "${self}/secrets/tor-onion-hostname.age";
      owner = "tor";
      group = "tor";
      mode = "0444";
    };

    services.tor = lib.mkIf cfg.tor.enable {
      enable = true;
      relay.onionServices.jetpham-website = {
        map = [
          {
            port = 80;
            target = {
              addr = "127.0.0.1";
              port = 8888;
            };
          }
        ];
      };
    };

    systemd.services.tor-onion-keys = lib.mkIf cfg.tor.enable {
      description = "Copy Tor onion keys into place";
      after = [ "agenix.service" ];
      before = [ "tor.service" ];
      wantedBy = [ "tor.service" ];
      serviceConfig.Type = "oneshot";
      script = ''
        dir="/var/lib/tor/onion/jetpham-website"
        mkdir -p "$dir"
        cp ${config.age.secrets.tor-onion-secret-key.path} "$dir/hs_ed25519_secret_key"
        cp ${config.age.secrets.tor-onion-public-key.path} "$dir/hs_ed25519_public_key"
        cp ${config.age.secrets.tor-onion-hostname.path} "$dir/hostname"
        chown -R tor:tor "$dir"
        chmod 700 "$dir"
        chmod 400 "$dir/hs_ed25519_secret_key"
        chmod 444 "$dir/hs_ed25519_public_key" "$dir/hostname"
      '';
    };
    # Q&A API systemd service
    systemd.services.jetpham-qa-api = {
      description = "Jet Pham Q&A API";
      after = [ "network.target" ];
      wantedBy = [ "multi-user.target" ];
      serviceConfig = {
        DynamicUser = true;
        StateDirectory = "jetpham-qa";
        Environment = [
          "QA_DB_PATH=/var/lib/jetpham-qa/qa.db"
          "QA_NOTIFY_EMAIL=${cfg.qaNotifyEmail}"
          "QA_MAIL_DOMAIN=${cfg.qaMailDomain}"
          "QA_REPLY_DOMAIN=${cfg.qaReplyDomain}"
        ];
        Restart = "on-failure";
        RestartSec = 5;
        LoadCredential = "webhook-secret:${webhookSecretPath}";
      };
      script = ''
        if [ ! -s "$CREDENTIALS_DIRECTORY/webhook-secret" ]; then
          echo "WEBHOOK_SECRET credential is empty" >&2
          exit 1
        fi

        export WEBHOOK_SECRET="$(cat "$CREDENTIALS_DIRECTORY/webhook-secret")"
        exec ${qaApi}/bin/jetpham-qa-api
      '';
    };

    services.caddy.virtualHosts.${cfg.domain} = {
      extraConfig = ''
        header Cross-Origin-Opener-Policy "same-origin"
        header Cross-Origin-Embedder-Policy "require-corp"

        handle /api/* {
          reverse_proxy 127.0.0.1:3003
        }

        handle /qa/rss.xml {
          reverse_proxy 127.0.0.1:3003
        }

        handle {
          root * ${package}
          try_files {path} /index.html
          file_server
        }
      '';
    };

    services.caddy.virtualHosts."http://:8888" = lib.mkIf cfg.tor.enable {
      extraConfig = ''
        bind 127.0.0.1
        header Cross-Origin-Opener-Policy "same-origin"
        header Cross-Origin-Embedder-Policy "require-corp"

        handle /api/* {
          reverse_proxy 127.0.0.1:3003
        }

        handle /qa/rss.xml {
          reverse_proxy 127.0.0.1:3003
        }

        handle {
          root * ${package}
          try_files {path} /index.html
          file_server
        }
      '';
    };
  };
}
