#!/usr/bin/env python3
"""In-place MRT/risk scan of EtherGold/logs landing (no archive)."""
from __future__ import annotations

import json
from collections import Counter
from datetime import datetime, timedelta
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1] / "logs"

RISK = {
    "mrt_risk_hand_reopen",
    "mrt_risk_hand_txn_restart",
    "mrt_risk_txn_restart_skip",
    "mrt_risk_late_0d_after_x1",
    "mrt_risk_arm_skip",
    "mrt_x9_empty_echo_reinject",
    "mrt_x9_empty_harvest_reinject",
    "mrt_x1_inferred_no_x9_retry",
    "mrt_x1_infer_skipped_hand_open",
    "status_0d_auto_close_miss",
}

CTX_KEEP = (
    "mrt_",
    "hs_",
    "hand_",
    "status_0",
    "inject_",
    "harvest",
    "x1",
    "x9",
    "wager",
    "scr_",
    "peer_",
    "packet_complete",
)


def parse_utc(u: str) -> datetime:
    return datetime.fromisoformat(u.replace("Z", "+00:00"))


def iter_events(pos: int):
    d = ROOT / str(pos) / "data"
    if not d.is_dir():
        return
    for f in d.glob("events.jsonl*"):
        with f.open("r", encoding="utf-8", errors="replace") as fh:
            for line in fh:
                line = line.strip()
                if not line:
                    continue
                try:
                    e = json.loads(line)
                except Exception:
                    continue
                e["_file"] = f.name
                yield e


def keep_ctx(ev: str) -> bool:
    if not ev:
        return False
    return any(tok in ev for tok in CTX_KEEP)


def main() -> None:
    print("=== RISK events by seat (UTC-sorted) ===")
    all_risk: dict[int, list] = {}
    for pos in (1, 2, 3, 4):
        hits = [e for e in iter_events(pos) if (e.get("ev") or "") in RISK]
        hits.sort(key=lambda e: e.get("utc") or "")
        all_risk[pos] = hits
        print(f"\npos{pos}: {len(hits)} risk events")
        for k, v in Counter(e.get("ev") for e in hits).most_common():
            print(f"  {v:4d}  {k}")
        print("  last 10:")
        for e in hits[-10:]:
            keys = {
                k: e.get(k)
                for k in ("tid", "seq", "reason", "path", "detail", "same_seq")
                if e.get(k) is not None
            }
            print(f"    {e.get('utc')}  {e.get('ev')}  {keys}  file={e['_file']}")

    # Glass-MRT proxies: hand_reopen + late_0d (txn_restart alone is common soft path)
    print("\n=== glass-MRT proxies (hand_reopen / late_0d_after_x1) ===")
    targets = []
    for pos, hits in all_risk.items():
        for e in hits:
            if e.get("ev") in ("mrt_risk_hand_reopen", "mrt_risk_late_0d_after_x1"):
                targets.append((pos, e))
    targets.sort(key=lambda t: t[1].get("utc") or "")
    for pos, e in targets:
        print(
            f"  pos{pos}  {e.get('utc')}  {e.get('ev')}  tid={e.get('tid')}  "
            f"reason={e.get('reason')}  file={e['_file']}"
        )

    # Focus: pos4 last risk cluster + any late_0d; witness +/-5s
    print("\n=== pos4 last RISK cluster + witness context ===")
    r4 = all_risk.get(4) or []
    if not r4:
        print("no pos4 risk")
        return
    focus = [e for e in r4 if e.get("ev") == "mrt_risk_late_0d_after_x1"]
    if not focus:
        focus = r4[-1:]
    for t in focus:
        utc = t.get("utc")
        print(f"\nTARGET pos4 {utc} {t.get('ev')} tid={t.get('tid')} file={t['_file']}")
        print(json.dumps({k: v for k, v in t.items() if not k.startswith("_")}, default=str)[:800])
        t0 = parse_utc(utc)
        win = timedelta(seconds=8)
        for label, pos in (("pos4", 4), ("pos41", 41), ("pos3", 3)):
            ctx = []
            for e in iter_events(pos):
                u = e.get("utc")
                if not u:
                    continue
                try:
                    dt = parse_utc(u)
                except Exception:
                    continue
                if abs(dt - t0) > win:
                    continue
                ev = e.get("ev") or ""
                if keep_ctx(ev):
                    ctx.append(e)
            ctx.sort(key=lambda e: e.get("utc") or "")
            print(f"  {label} +/-8s keep={len(ctx)}")
            for e in ctx[:60]:
                bits = {
                    k: e.get(k)
                    for k in ("tid", "opcode", "seq", "reason", "silk", "signal", "slv_in")
                    if e.get(k) is not None
                }
                print(f"    {e.get('utc')}  {e.get('ev')}  {bits}")
            if len(ctx) > 60:
                print(f"    ... +{len(ctx) - 60} more")

    # Bank summary: txn_restart counts (often soft) vs reopen/late
    print("\n=== bank summary ===")
    for pos, hits in all_risk.items():
        c = Counter(e.get("ev") for e in hits)
        print(
            f"pos{pos}: reopen={c.get('mrt_risk_hand_reopen', 0)} "
            f"txn_restart={c.get('mrt_risk_hand_txn_restart', 0)} "
            f"late_0d={c.get('mrt_risk_late_0d_after_x1', 0)} "
            f"empty_echo_reinject={c.get('mrt_x9_empty_echo_reinject', 0)} "
            f"0d_miss={c.get('status_0d_auto_close_miss', 0)}"
        )


if __name__ == "__main__":
    main()
