# Results dashboard (§4.5, D7): the YunoHost-CI-like overview at ci.commoninternet.net. Reads the
# Drone API (read-only) and renders latest-run-per-recipe + SVG badges. Packaged as a Nix-built OCI
# image and run as a swarm service on `proxy`, routed by traefik at Host(ci.commoninternet.net) — the
# comment-bridge's Host && PathPrefix(`/hook`) rule is longer, so /hook still wins (priority by rule
# length). Deployed by an idempotent-reconcile oneshot (same pattern as bridge/drone).
{ pkgs, ... }:
let
  dashApp = pkgs.runCommand "cc-ci-dashboard-app" { } ''
    mkdir -p $out/app
    cp ${../../dashboard/dashboard.py} $out/app/dashboard.py
  '';

  # Content-derived tag: changes whenever dashboard.py changes, so `docker stack deploy` actually
  # rolls the service to the new image (a fixed `:latest` tag + unchanged stack spec does NOT roll —
  # swarm sees no change). Reproducible + self-healing.
  imageTag = builtins.substring 0 12 (builtins.hashString "sha256"
    (builtins.readFile ../../dashboard/dashboard.py));

  image = pkgs.dockerTools.buildLayeredImage {
    name = "cc-ci-dashboard";
    tag = imageTag;
    contents = [ pkgs.python3 pkgs.cacert dashApp ];
    config = {
      Cmd = [ "${pkgs.python3}/bin/python3" "/app/dashboard.py" ];
      Env = [ "SSL_CERT_FILE=${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt" ];
      ExposedPorts = { "8080/tcp" = { }; };
    };
  };

  stack = pkgs.writeText "cc-ci-dashboard-stack.yml" ''
    version: "3.8"
    services:
      app:
        image: cc-ci-dashboard:${imageTag}
        environment:
          - DRONE_URL=https://drone.ci.commoninternet.net
          - CI_REPO=recipe-maintainers/cc-ci
          - DASH_LISTEN=0.0.0.0:8080
          - DRONE_TOKEN_FILE=/run/secrets/drone_token
          - CCCI_RUNS_DIR=/var/lib/cc-ci-runs
        secrets:
          - drone_token
        # Phase 3 (U2.3): the per-run artifacts (results.json, summary.png, screenshot.png, badge.svg)
        # the runner writes under /var/lib/cc-ci-runs are bind-mounted READ-ONLY so the dashboard can
        # serve them at /runs/<id>/<file>. Read-only: the dashboard never writes run artifacts.
        volumes:
          - type: bind
            source: /var/lib/cc-ci-runs
            target: /var/lib/cc-ci-runs
            read_only: true
        networks:
          - proxy
        deploy:
          replicas: 1
          restart_policy:
            condition: any
          labels:
            - "traefik.enable=true"
            - "traefik.http.services.ccci-dashboard.loadbalancer.server.port=8080"
            - "traefik.http.routers.ccci-dashboard.rule=Host(`ci.commoninternet.net`)"
            - "traefik.http.routers.ccci-dashboard.entrypoints=web-secure"
            - "traefik.http.routers.ccci-dashboard.tls=true"
    networks:
      proxy:
        external: true
    secrets:
      drone_token:
        external: true
        name: cc_ci_dashboard_drone_token_v1
  '';

  reconcile = pkgs.writeShellApplication {
    name = "cc-ci-reconcile-dashboard";
    runtimeInputs = with pkgs; [ docker coreutils ];
    text = ''
      if [ ! -r /run/secrets/bridge_drone_token ]; then
        echo "FATAL: /run/secrets/bridge_drone_token missing (rebuild ordering?)" >&2
        exit 1
      fi
      docker load -i ${image}
      # Dashboard reads the Drone API read-only; reuse the same Drone token value as the bridge.
      docker secret inspect cc_ci_dashboard_drone_token_v1 >/dev/null 2>&1 \
        || docker secret create cc_ci_dashboard_drone_token_v1 /run/secrets/bridge_drone_token >/dev/null
      docker stack deploy --detach=true -c ${stack} ccci-dashboard
    '';
  };
in
{
  systemd.services.deploy-dashboard = {
    description = "Reconcile the cc-ci results dashboard (overview + badges) swarm service";
    # Serialized after deploy-bridge (chain proxy→drone→bridge→dashboard→backupbot) to avoid the
    # concurrent abra-init race on a fresh host (see bridge.nix). Ordering-only.
    after = [ "deploy-bridge.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-dashboard";
    };
  };
}
