"""Turn the lab notebook's JSON lines into the lab's results table.

Purpose: read the records run-agent-task.sh appended to labbook.md and print one row per
    tool and model, so the comparison in the "one task, six agents" lab is produced from
    the recorded runs rather than retyped by hand.
Platform: all (spark, strix, mac, nvidia). Standard library only.
Minimum memory: none of consequence.
Assumes: labbook.md contains one JSON object per line for lab
    "part-25-one-task-six-agents", written by run-agent-task.sh. Lines that are not JSON
    are ignored, so a notebook that also contains prose is fine.
Usage:
    python3 summarise-agent-runs.py labbook.md
    python3 summarise-agent-runs.py labbook.md --model local/coder
    python3 summarise-agent-runs.py labbook.md --format markdown
"""

from __future__ import annotations

import argparse
import json
from pathlib import Path

LAB = "part-25-one-task-six-agents"
COLUMNS = ("Tool", "Model alias", "Outcome", "Wall clock s", "Tokens", "Lines changed")


def read_records(path: Path, lab: str) -> list[dict]:
    """Every JSON line in the notebook that belongs to this lab."""
    records = []
    for line in path.read_text(encoding="utf-8", errors="replace").splitlines():
        line = line.strip()
        if not line.startswith("{"):
            continue
        try:
            record = json.loads(line)
        except json.JSONDecodeError:
            continue
        if record.get("lab") == lab:
            records.append(record)
    return records


def outcome(record: dict) -> str:
    """A single word for what happened, which is what the results table wants."""
    if record.get("tests_were_edited"):
        return "invalid (tests edited)"
    if record.get("tests_pass"):
        return "pass"
    if record.get("tool_exit_status", 0) != 0:
        return "tool error"
    return "fail"


def to_rows(records: list[dict]) -> list[list[str]]:
    rows = []
    for record in records:
        tokens = record.get("tokens")
        rows.append(
            [
                str(record.get("tool", "?")),
                str(record.get("model_alias", "?")),
                outcome(record),
                str(record.get("wall_clock_seconds", "")),
                "not recorded" if tokens is None else str(tokens),
                str(record.get("changed_lines", "")),
            ]
        )
    return rows


def render_fixed_width(rows: list[list[str]]) -> str:
    widths = [len(name) for name in COLUMNS]
    for row in rows:
        for index, cell in enumerate(row):
            widths[index] = max(widths[index], len(cell))
    lines = ["  ".join(name.ljust(widths[i]) for i, name in enumerate(COLUMNS))]
    lines.append("  ".join("-" * width for width in widths))
    for row in rows:
        lines.append("  ".join(cell.ljust(widths[i]) for i, cell in enumerate(row)))
    return "\n".join(lines)


def render_markdown(rows: list[list[str]]) -> str:
    lines = ["| " + " | ".join(COLUMNS) + " |"]
    lines.append("| " + " | ".join("---" for _ in COLUMNS) + " |")
    for row in rows:
        lines.append("| " + " | ".join(row) + " |")
    return "\n".join(lines)


def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
    parser.add_argument("labbook", help="path to labbook.md")
    parser.add_argument("--model", default=None, help="only rows for this model alias")
    parser.add_argument(
        "--format",
        choices=("fixed", "markdown"),
        default="fixed",
        help="fixed-width for the terminal, markdown to paste into your notes",
    )
    args = parser.parse_args()

    path = Path(args.labbook)
    if not path.exists():
        print(f"No lab notebook at {path}. Run run-agent-task.sh first.")
        return 1

    records = read_records(path, LAB)
    if args.model:
        records = [r for r in records if r.get("model_alias") == args.model]

    if not records:
        print(f"No records for lab {LAB} in {path}.")
        return 1

    records.sort(key=lambda r: (r.get("model_alias", ""), r.get("tool", "")))
    rows = to_rows(records)

    if args.format == "markdown":
        print(render_markdown(rows))
    else:
        print(render_fixed_width(rows))

    passes = sum(1 for r in records if outcome(r) == "pass")
    print()
    print(f"{passes} of {len(records)} recorded runs left the test suite passing.")
    print("Every number above is one run. Repeat each row before drawing a conclusion.")
    return 0


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