"""Aggregate B2 microbench cells into a single interference-index sweep summary.

Per cell (variant × prefill_size):
- read metrics.jsonl + run_window.json
- slice the shared engine_*.jsonl by run window
- run interference_index() against the slice
- record (variant, prefill_size, n_overlap, n_clean, tpot_p90_*, idx)
"""

from __future__ import annotations

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

from analysis.characterization.joined_analysis import (
    _percentile,
    _vllm_rid_matches,
    interference_index,
    load_engine_state,
    load_jsonl,
    write_json,
)


def _slice_engine_state(
    engine_state_by_worker: dict[str, list[dict]],
    t_start: float,
    t_end: float,
) -> dict[str, list[dict]]:
    sliced: dict[str, list[dict]] = {}
    for worker, steps in engine_state_by_worker.items():
        sliced[worker] = [s for s in steps
                          if t_start <= (s.get("t_unix") or 0.0) <= t_end]
    return sliced


def _to_joined_shape(metrics_rows: list[dict], variant: str) -> list[dict]:
    """Adapt B2 metric rows to what interference_index expects."""
    joined: list[dict] = []
    for r in metrics_rows:
        if r.get("workload") != "decode":
            continue
        joined.append({
            "request_id": r["request_id"],
            "tpot_s": r.get("tpot_s"),
            "ttft_s": r.get("ttft_s"),
            "latency_s": r.get("latency_s"),
            "endpoint_url": r.get("endpoint"),
            "routed_to": r.get("endpoint"),
            "t_first_token_unix": (
                (r["t_dispatch_unix"] + r["ttft_s"])
                if r.get("ttft_s") is not None
                and r.get("t_dispatch_unix") is not None else None
            ),
            "t_finish_unix": r.get("t_finish_unix"),
            "error": r.get("error"),
        })
    return joined


def main() -> None:
    p = argparse.ArgumentParser(description="B2 sweep aggregation")
    p.add_argument("--sweep-dir", type=Path, required=True,
                   help="Top-level dir produced by scripts/b2_interference.py")
    p.add_argument("--engine-state-dir", type=Path, required=True)
    p.add_argument("--worker-map", type=str, required=True,
                   help="URL=worker_id pairs, comma-separated")
    p.add_argument("--out", type=Path, default=None)
    args = p.parse_args()

    worker_map = {}
    for entry in args.worker_map.split(","):
        url, _, wid = entry.strip().partition("=")
        if url and wid:
            worker_map[url] = wid

    engine_state = load_engine_state(args.engine_state_dir)
    rows: list[dict] = []
    for variant_dir in sorted(args.sweep_dir.glob("*/")):
        if variant_dir.name in ("logs",):
            continue
        for cell_dir in sorted(variant_dir.glob("p*/")):
            window_path = cell_dir / "run_window.json"
            metrics_path = cell_dir / "metrics.jsonl"
            if not window_path.exists() or not metrics_path.exists():
                continue
            window = json.loads(window_path.read_text())
            metrics_rows = load_jsonl(metrics_path)
            joined = _to_joined_shape(metrics_rows, variant_dir.name)
            sliced = _slice_engine_state(
                engine_state, window["t_start_unix"], window["t_end_unix"],
            )
            idx = interference_index(joined, sliced, worker_map)
            rows.append({
                "variant": variant_dir.name,
                "prefill_size": int(window["prefill_size"]),
                "decode_endpoint": window["decode_endpoint"],
                "prefill_endpoint": window["prefill_endpoint"],
                "n_decode_requests": sum(1 for r in metrics_rows
                                          if r.get("workload") == "decode"
                                          and r.get("error") is None),
                "n_prefill_injections": sum(1 for r in metrics_rows
                                             if r.get("workload") == "prefill"
                                             and r.get("error") is None),
                **idx,
            })
    summary = {"rows": rows}
    out_path = args.out or args.sweep_dir / "b2_sweep_summary.json"
    write_json(out_path, summary)
    print(json.dumps(rows, indent=2))


if __name__ == "__main__":
    main()
