#!/usr/bin/env python3
"""Build public/traces/manifest.json from the captured fixtures.

The manifest is what the browser reads to know which runs exist. It is
generated rather than hand-written so a fixture can never be referenced without
existing, or exist without being referenced.
"""

from __future__ import annotations

import json
from pathlib import Path

TRACES = Path(__file__).parent.parent / "public" / "traces"

ARMS = {
    "base-off": ("Out of the box", "recorded"),
    "base-on": ("Allowed to think", "intervened"),
    "solver": ("Best-known play", "generated"),
    "cautious": ("Never wastes a guess", "generated"),
}

# What was done to the run, for arms that had something done to them. Required
# by the contract on any `intervened` run so that a sampling change can never be
# presented as a training result by omitting to mention it.
INTERVENTIONS = {
    "base-on": "Same model, same seeds, sampled with thinking enabled. No training, no fine-tuning.",
}

ORDER = ["base-off", "base-on", "solver", "cautious"]


def main() -> int:
    manifest: dict[str, list[dict]] = {}

    for demo_dir in sorted(p for p in TRACES.iterdir() if p.is_dir()):
        runs = []
        for path in sorted(demo_dir.glob("*.json")):
            data = json.loads(path.read_text())
            arm = data["runId"].rsplit("-s", 1)[0]
            label, kind = ARMS.get(arm, (arm, "recorded"))
            run = {
                "id": data["runId"],
                "label": label,
                "path": f"/traces/{demo_dir.name}/{path.name}",
                "kind": kind,
                "model": data["model"],
                "capturedAt": data["capturedAt"],
                "seed": data["seed"],
            }
            if arm in INTERVENTIONS:
                run["intervention"] = INTERVENTIONS[arm]
            runs.append(run)

        runs.sort(key=lambda r: (ORDER.index(r["id"].rsplit("-s", 1)[0])
                                 if r["id"].rsplit("-s", 1)[0] in ORDER else 99,
                                 r["seed"]))
        if runs:
            manifest[demo_dir.name] = runs

    out = TRACES / "manifest.json"
    out.write_text(json.dumps(manifest, indent=2) + "\n")

    for slug, runs in manifest.items():
        by_arm: dict[str, list[dict]] = {}
        for r in runs:
            by_arm.setdefault(r["id"].rsplit("-s", 1)[0], []).append(r)
        print(f"{slug}: {len(runs)} runs")
        for arm, group in by_arm.items():
            solved = 0
            for r in group:
                data = json.loads((TRACES.parent / r["path"].lstrip("/")).read_text())
                solved += 1 if data["outcome"] == "solved" else 0
            print(f"  {arm:<10} {len(group)} runs, solved {solved}/{len(group)}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
