"""Totals, medians and cost per setup across both runs, from runs.json (IKEA excluded from scoring: its product URL redirected on the test day)."""
import json, statistics as S, collections
# Fixed prefix (tools + system) that a harness caches once and reuses across tasks. Playwright's 6,777 was measured in separate runs
# with the prefix cached across tasks (first-turn cache_read); the others are each task's first-turn total minus the same task's user message, taken from Playwright's runs.
# agent-browser tool only (377 tokens) is below Opus 5.5's 512-token caching minimum.
PREFIX = {"agent-browser": 14014, "playwright-mcp": 6777, "devtools-mcp": 11060, "agent-browser-noskill": 0, "agent-browser-lite": 519, "agent-browser-agentsmd": 527, "agent-browser-mcp": 31001}
PRICE = {"input": 4.0, "cache_write": 5.0, "cache_read": 0.20, "output": 20.0}  # USD per million tokens, Claude Opus 5.5
tasks = [t["id"] for t in json.load(open("tasks.json"))]
rows = collections.defaultdict(list)
for d in json.load(open("runs.json")):  # one entry per run; the research version read one file per run
    run, tool, tid = d["run"], d["setup"], d["task"]
    t = d["totals"]
    cost = sum(t[k] * PRICE[k] for k in PRICE) / 1e6
    p = PREFIX[tool]  # with a cached prefix, turn 1 reads the prefix instead of writing it
    cost_cached = cost - (p * (PRICE["cache_write"] - PRICE["cache_read"]) / 1e6 if p and d["turns"][0]["cache_write"] >= p else 0)
    peak = max(x["input"] + x["cache_read"] + x["cache_write"] for x in d["turns"])
    js = sum(1 for c in d["tool_calls"] if ("eval" in json.dumps(c["input"]) or c["name"] in ("browser_evaluate", "evaluate_script", "browser_run_code_unsafe", "agent_browser_eval")))
    snaps = sum(1 for c in d["tool_calls"] if ("snapshot" in json.dumps(c["input"]) or c["name"] in ("browser_snapshot", "take_snapshot", "agent_browser_snapshot")))
    rows[tool].append({"task": tid, "run": run, "in": t["input_all"], "out": t["output"], "turns": len(d["turns"]), "calls": len(d["tool_calls"]),
                       "secs": d["secs"], "cost": cost, "cost_cached": cost_cached, "peak": peak, "js": js, "snaps": snaps, "errors": sum(c["error"] for c in d["tool_calls"]), "big": sum(c["chars"] > 50000 for c in d["tool_calls"])})
summary = {}
for tool, rs in rows.items():
    sc = [r for r in rs if r["task"] != "ikea-billy"]
    summary[tool] = {"runs": len(sc), "median_input_tokens": S.median(r["in"] for r in sc), "total_input_tokens": sum(r["in"] for r in sc),
                     "median_output_tokens": S.median(r["out"] for r in sc), "median_turns": S.median(r["turns"] for r in sc),
                     "median_calls": S.median(r["calls"] for r in sc), "median_secs": S.median(r["secs"] for r in sc),
                     "total_cost_usd": round(sum(r["cost"] for r in sc), 2), "median_cost_usd": round(S.median(r["cost"] for r in sc), 4), "median_cost_usd_prefix_cached": round(S.median(r["cost_cached"] for r in sc), 4),
                     "js_calls_share": round(sum(r["js"] for r in sc) / max(1, sum(r["calls"] for r in sc)), 2),
                     "snapshot_calls_share": round(sum(r["snaps"] for r in sc) / max(1, sum(r["calls"] for r in sc)), 2),
                     "tool_errors": sum(r["errors"] for r in sc), "max_input_tokens": max(r["in"] for r in sc),
                     "mean_input_tokens": round(S.mean(r["in"] for r in sc)), "p90_input_tokens": sorted(r["in"] for r in sc)[int(0.9 * len(sc))],
                     "total_secs": round(sum(r["secs"] for r in sc)), "median_peak_context": S.median(r["peak"] for r in sc),
                     "max_peak_context": max(r["peak"] for r in sc), "big_outputs_over_50k_chars": sum(r["big"] for r in sc),
                     # first task of each run still writes the prefix once
                     "total_cost_usd_prefix_cached": round(sum(r["cost_cached"] for r in sc) + 2 * PREFIX[tool] * (PRICE["cache_write"] - PRICE["cache_read"]) / 1e6, 2)}
print(json.dumps(summary, indent=1))
# per-task cheapest tool, with and without the no-skill variant (by mean input tokens over 2 runs)
wins, wins3 = collections.Counter(), collections.Counter()
for tid in tasks:
    if tid == "ikea-billy": continue
    m = {tool: S.mean(r["in"] for r in rows[tool] if r["task"] == tid) for tool in rows}
    wins[min(m, key=m.get)] += 1
    [m.pop(k, None) for k in ("agent-browser-noskill", "agent-browser-lite", "agent-browser-agentsmd")]; wins3[min(m, key=m.get)] += 1
print("fewest input tokens, tasks won (4 setups):", dict(wins))
print("fewest input tokens, tasks won (3 vendor setups):", dict(wins3))
json.dump({"summary": summary, "rows": rows, "wins": wins, "wins_vendor_setups": wins3}, open("phase_b_summary.json", "w"), indent=1)
