"""What one run of the effort test did, how long it took and what it spent, read from the session's own transcript.

  python tools/runstats.py <transcript.jsonl> <run folder> [--json out.json]

The transcript is the subagent's JSONL (the harness's task output file). Tokens are summed once per API message (the
last usage seen for each message id), priced at Claude Opus 5.5 API rates (claude-api skill, cached 2026-10-06):
input $4, output $20, cache read $0.20, cache write 1.25x input for the 5-minute cache and 2x for the 1-hour cache, all
per million tokens. Minutes come from the run's RUN.md (its `date` lines) and from the transcript's first and last
timestamps.
"""
import json
import os
import re
import sys
from collections import Counter
from datetime import datetime

PRICE = dict(input=4.00, output=20.00, cache_read=0.20, write_5m=5.00, write_1h=8.00)   # $ per million tokens


def load(path):
    rows = []
    for line in open(path, encoding='utf-8', errors='replace'):
        line = line.strip()
        if line:
            try:
                rows.append(json.loads(line))
            except json.JSONDecodeError:
                pass
    return rows


def stamp(s):
    try:
        return datetime.fromisoformat(s.replace('Z', '+00:00'))
    except (AttributeError, ValueError):
        return None


def run_minutes(folder):
    p = os.path.join(folder, 'RUN.md')
    if not os.path.exists(p):
        return None
    ts = re.findall(r'(\d{1,2}):(\d{2}):(\d{2})', open(p, encoding='utf-8').read())
    if len(ts) < 2:
        return None
    a, b = [int(h) * 3600 + int(m) * 60 + int(s) for h, m, s in ts[:2]]
    return (b - a) / 60


def stats(transcript, folder):
    rows = load(transcript)
    usage, tools, skills, steps = {}, Counter(), [], []
    times = [t for t in (stamp(r.get('timestamp')) for r in rows) if t]
    for r in rows:
        msg = r.get('message') or {}
        if r.get('type') != 'assistant' or not isinstance(msg, dict):
            continue
        if msg.get('id') and msg.get('usage'):
            usage[msg['id']] = msg['usage']
        for c in msg.get('content') or []:
            if not isinstance(c, dict) or c.get('type') != 'tool_use':
                continue
            name, inp = c.get('name', '?'), c.get('input') or {}
            tools[name] += 1
            if name == 'Skill':
                skills.append(inp.get('skill', '?'))
            elif name == 'Bash' or name == 'PowerShell':
                cmd = inp.get('command', '')
                for key, label in (('hyperframes check', 'check'), ('hyperframes snapshot', 'snapshot'),
                                   ('hyperframes lint', 'lint'), ('ffmpeg', 'ffmpeg'), ('ffprobe', 'ffprobe')):
                    if key in cmd:
                        steps.append(label)
            elif name == 'Write':
                steps.append('write ' + os.path.basename(inp.get('file_path', '')))
            elif name == 'Read' and str(inp.get('file_path', '')).lower().endswith(('.png', '.jpg', '.jpeg')):
                steps.append('look at a still')
    tok = Counter()
    for u in usage.values():
        tok['input'] += u.get('input_tokens', 0) or 0
        tok['output'] += u.get('output_tokens', 0) or 0
        tok['cache_read'] += u.get('cache_read_input_tokens', 0) or 0
        cc = u.get('cache_creation') or {}
        w5, w1 = cc.get('ephemeral_5m_input_tokens', 0) or 0, cc.get('ephemeral_1h_input_tokens', 0) or 0
        if not (w5 or w1):
            w5 = u.get('cache_creation_input_tokens', 0) or 0
        tok['write_5m'] += w5
        tok['write_1h'] += w1
    cost = sum(tok[k] * PRICE[k] / 1e6 for k in PRICE)
    return dict(
        transcript=transcript, folder=folder,
        minutes_run_md=run_minutes(folder),
        minutes_transcript=((max(times) - min(times)).total_seconds() / 60) if len(times) > 1 else None,
        api_calls=len(usage), tokens=dict(tok), tokens_total=sum(tok.values()), dollars=round(cost, 2),
        tool_calls=sum(tools.values()), tools=dict(tools.most_common()), skills=skills,
        checks=steps.count('check'), snapshots=steps.count('snapshot'), stills_looked_at=steps.count('look at a still'),
        files_written=[s[6:] for s in steps if s.startswith('write ')],
    )


if __name__ == '__main__':
    s = stats(sys.argv[1], sys.argv[2])
    if '--json' in sys.argv:
        json.dump(s, open(sys.argv[sys.argv.index('--json') + 1], 'w', encoding='utf-8'), indent=1)
    print(json.dumps({k: v for k, v in s.items() if k not in ('transcript',)}, indent=1))
