# Recipe Report static site (report.ci.commoninternet.net): a public nginx serving the weekly
# "Recipe Report" HTML pages written to /var/lib/cc-ci-reports by the /recipe-report skill. No app,
# no secrets — just static files behind traefik + the wildcard TLS (same pattern as dashboard.nix,
# but a plain nginx:alpine since there's nothing to render server-side). Content is updated by writing
# files into /var/lib/cc-ci-reports; nginx serves them live (no redeploy needed).
#
# It ALSO serves a same-origin realtime PR-status proxy at /pr/<recipe>/<n>: the report's STATUS
# column fetches it client-side to show each PR's live state (open vs. ✓). Same-origin means no
# dependency on the Gitea CORS allow-list; the recipe mirrors are public so no token is needed. The
# proxy is pinned to recipe-maintainers + a safe recipe-name charset and is read-only (GET/HEAD).
{ pkgs, ... }:
let
  reportsDir = "/var/lib/cc-ci-reports";

  # Custom nginx server: static report files + the /pr/<recipe>/<n> → Gitea-API proxy. Replaces the
  # stock /etc/nginx/conf.d/default.conf (which the image's nginx.conf includes inside http{}).
  nginxConf = pkgs.writeText "cc-ci-reports-default.conf" ''
    server {
        listen 80;
        server_name _;
        root /usr/share/nginx/html;
        index index.html;

        # Realtime PR-status proxy for the Recipe Report STATUS column.
        # GET /pr/<recipe>/<n> -> the PUBLIC Gitea PR JSON ({state, merged, ...}). Same-origin from
        # the browser's view, so no CORS dependency; unauthenticated, since the recipe mirrors are
        # public. The repo owner is hard-pinned to recipe-maintainers and the recipe name to a
        # slashless charset, so the proxied path can only ever address recipe-maintainers/<name>/pulls
        # (it cannot be coerced to another org or path). Only safe read methods are allowed.
        location ~ ^/pr/([a-z0-9._-]+)/([0-9]+)$ {
            limit_except GET HEAD { deny all; }
            resolver 127.0.0.11 ipv6=off valid=30s;   # docker embedded DNS (forwards external names)
            proxy_ssl_server_name on;
            proxy_set_header Host git.autonomic.zone;
            proxy_set_header Accept "application/json";
            proxy_pass https://git.autonomic.zone/api/v1/repos/recipe-maintainers/$1/pulls/$2;
            proxy_intercept_errors off;
            proxy_connect_timeout 5s;
            proxy_read_timeout 10s;
            add_header Cache-Control "no-store" always;  # always fetch live state, never cache in the browser
        }

        location / {
            try_files $uri $uri/ =404;
        }
    }
  '';

  stack = pkgs.writeText "cc-ci-reports-stack.yml" ''
    version: "3.8"
    services:
      app:
        image: nginx:alpine
        volumes:
          - type: bind
            source: ${reportsDir}
            target: /usr/share/nginx/html
            read_only: true
          - type: bind
            source: ${nginxConf}
            target: /etc/nginx/conf.d/default.conf
            read_only: true
        networks:
          - proxy
        deploy:
          replicas: 1
          restart_policy:
            condition: any
          labels:
            - "traefik.enable=true"
            - "traefik.http.services.ccci-reports.loadbalancer.server.port=80"
            - "traefik.http.routers.ccci-reports.rule=Host(`report.ci.commoninternet.net`)"
            - "traefik.http.routers.ccci-reports.entrypoints=web-secure"
            - "traefik.http.routers.ccci-reports.tls=true"
    networks:
      proxy:
        external: true
  '';

  reconcile = pkgs.writeShellApplication {
    name = "cc-ci-reconcile-reports";
    runtimeInputs = with pkgs; [ docker coreutils ];
    text = ''
      mkdir -p ${reportsDir}
      # Seed a placeholder index so the site serves something before the first report is generated.
      if [ ! -f ${reportsDir}/index.html ]; then
        cat > ${reportsDir}/index.html <<'HTML'
      <!doctype html><html lang="en"><head><meta charset="utf-8">
      <meta name="viewport" content="width=device-width,initial-scale=1">
      <title>The Recipe Report</title>
      <style>body{font:16px/1.5 system-ui,sans-serif;max-width:50rem;margin:3rem auto;padding:0 1rem;color:#222}</style>
      </head><body><h1>🌻 The Recipe Report</h1>
      <p>No reports yet — the first one is generated after the weekly recipe-upgrade run.</p>
      </body></html>
      HTML
      fi
      docker stack deploy --detach=true -c ${stack} ccci-reports
    '';
  };
in
{
  systemd.services.deploy-reports = {
    description = "Reconcile the cc-ci Recipe Report static site (report.ci.commoninternet.net)";
    # Ordering-only: chain after the dashboard (proxy→…→dashboard→reports) to avoid concurrent
    # docker-init races on a fresh host.
    after = [ "deploy-dashboard.service" "deploy-proxy.service" "swarm-init.service" "docker.service" "network-online.target" ];
    requires = [ "swarm-init.service" "docker.service" ];
    wants = [ "network-online.target" ];
    wantedBy = [ "multi-user.target" ];
    serviceConfig = {
      Type = "oneshot";
      RemainAfterExit = true;
      ExecStart = "${reconcile}/bin/cc-ci-reconcile-reports";
    };
  };
}
