#!/usr/bin/env python3
from __future__ import annotations

"""Aggregate fail-only NDJSON logs into a concise Markdown report."""

import argparse
import json
from collections import defaultdict
from pathlib import Path
from typing import Any


def parse_args() -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="Aggregate fail-only NDJSON into Markdown summary",
    )
    parser.add_argument("--input", default="reports/llm_fail.ndjson")
    parser.add_argument("--output", default="reports/llm_fail_summary.md")
    parser.add_argument("--top", type=int, default=50)
    return parser.parse_args()


def load_ndjson(path: Path) -> list[dict[str, Any]]:
    if not path.exists():
        return []

    records: list[dict[str, Any]] = []
    for line in path.read_text(encoding="utf-8").splitlines():
        payload = line.strip()
        if not payload:
            continue
        try:
            records.append(json.loads(payload))
        except Exception:
            continue
    return records


def aggregate(records: list[dict[str, Any]]) -> dict[str, Any]:
    by_test = defaultdict(
        lambda: {
            "failed": 0,
            "error": 0,
            "crashed": 0,
            "last_phase": None,
            "last_duration_s": 0.0,
        },
    )

    failed = error = crashed = 0
    workers: set[str] = set()

    for record in records:
        if record.get("event") != "test_phase":
            continue

        outcome = str(record.get("outcome", ""))
        if outcome not in {"failed", "error", "crashed"}:
            continue

        test_id = str(record.get("test_id", ""))
        by_test[test_id][outcome] += 1
        by_test[test_id]["last_phase"] = record.get("phase")
        try:
            by_test[test_id]["last_duration_s"] = float(record.get("duration_s", 0.0) or 0.0)
        except Exception:
            pass

        if outcome == "failed":
            failed += 1
        elif outcome == "error":
            error += 1
        else:
            crashed += 1

        worker = record.get("worker_id")
        if worker:
            workers.add(str(worker))

    return {
        "by_test": by_test,
        "failed": failed,
        "error": error,
        "crashed": crashed,
        "workers": workers,
    }


def to_markdown(summary: dict[str, Any], records: list[dict[str, Any]], top_n: int) -> str:
    total = summary["failed"] + summary["error"] + summary["crashed"]
    workers = ", ".join(sorted(summary["workers"])) if summary["workers"] else "-"
    lines: list[str] = []

    lines.append("# Fail-only NDJSON Summary")
    lines.append(
        f"- Total fail events: {total} "
        f"(failed={summary['failed']}, error={summary['error']}, crashed={summary['crashed']})",
    )
    lines.append(f"- Workers: {workers}")

    items = list(summary["by_test"].items())
    items.sort(key=lambda kv: kv[1]["failed"] + kv[1]["error"] + kv[1]["crashed"], reverse=True)
    if items:
        lines.append("## Top Failing Tests")
        lines.append("| # | Test ID | failed | error | crashed | last_phase | last_duration_s |")
        lines.append("|---:|---|---:|---:|---:|---|---:|")
        for index, (test_id, counts) in enumerate(items[:top_n], 1):
            lines.append(
                f"| {index} | {test_id} | {counts['failed']} | {counts['error']} | "
                f"{counts['crashed']} | {counts.get('last_phase') or '-'} | "
                f"{counts.get('last_duration_s', 0.0):.3f} |",
            )
        lines.append("")
    else:
        lines.append("> No failing events were recorded.")

    session_summary: dict[str, Any] | None = None
    for record in reversed(records):
        if record.get("event") == "session_summary":
            session_summary = record
            break

    if session_summary:
        lines.append("## Session Summary")
        lines.append("```json")
        lines.append(json.dumps(session_summary, ensure_ascii=False, indent=2))
        lines.append("```")

    return "\n".join(lines) + "\n"


def main() -> int:
    args = parse_args()
    input_path = Path(args.input)
    output_path = Path(args.output)
    output_path.parent.mkdir(parents=True, exist_ok=True)

    records = load_ndjson(input_path)
    summary = aggregate(records)
    markdown = to_markdown(summary, records, args.top)
    output_path.write_text(markdown, encoding="utf-8")
    print(output_path)
    return 0


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