"""run_all.py

Reruns every exercise program and the figure generator, then compares each
check value file against a saved copy.

A rerun after a change that should affect only text, such as a spelling
correction, must reproduce every computed number exactly. Any difference in a
check value file means the change touched the analysis, and the run reports it.

    python run_all.py --save      copy current check values to a baseline
    python run_all.py             rerun everything and compare
"""
from __future__ import annotations

import json
import shutil
import subprocess
import sys
import time
from pathlib import Path

HERE = Path(__file__).resolve().parent
SNAP = HERE.parent / "snapshots"
BASE = HERE.parent / "_baseline_checkvalues"

PROGRAMS = ["exercise_0a.py", "exercise_0b.py", "exercise_0c.py",
            "exercise_1a.py", "exercise_1b.py", "exercise_3a.py",
            "exercise_2b.py", "exercise_3b.py", "exercise_4a.py",
            "exercise_4b.py", "exercise_5a.py", "exercise_5b.py",
            "asi_toolkit.py", "classification_demo.py",
            "cooling_centers_analysis.py", "make_figures.py",
            "harness_template.py"]


def save():
    BASE.mkdir(exist_ok=True)
    for f in SNAP.glob("*checkvalues.json"):
        shutil.copy2(f, BASE / f.name)
    print(f"baseline saved: {len(list(BASE.glob('*.json')))} files")


def run():
    failed = []
    for p in PROGRAMS:
        t0 = time.time()
        r = subprocess.run([sys.executable, p], cwd=str(HERE),
                           capture_output=True, text=True, timeout=1800)
        dt = time.time() - t0
        ok = r.returncode == 0 and "FAILED" not in r.stdout
        print(f"  {'ok  ' if ok else 'FAIL'} {p:<32} {dt:6.1f} s", flush=True)
        if not ok:
            failed.append(p)
            print("      " + (r.stderr or r.stdout)[-400:].replace("\n", "\n      "))
    return failed


def compare():
    diffs = []
    for b in sorted(BASE.glob("*.json")):
        cur = SNAP / b.name
        if not cur.exists():
            diffs.append((b.name, "missing after rerun"))
            continue
        a, c = json.loads(b.read_text()), json.loads(cur.read_text())
        if a != c:
            diffs.append((b.name, "values changed"))
    return diffs


if __name__ == "__main__":
    if "--save" in sys.argv:
        save()
        raise SystemExit(0)
    print("rerunning every program")
    failed = run()
    diffs = compare()
    print(f"\nprograms failed : {len(failed)}")
    print(f"check value files compared : {len(list(BASE.glob('*.json')))}")
    for name, why in diffs:
        print(f"   DIFFERENT  {name}: {why}")
    print("RESULT:", "IDENTICAL" if not diffs and not failed else "CHANGED")
