#!/usr/bin/env python3
"""Compact ZSCHED trace-vs-model summary.

Use after tb_top_psmct32_sh3_zsched regenerates sim/traces/rtl/zsched_*.txt.
It compares the current feeder-derived fixed-point model against the RTL issue
and fragment traces, split by epoch.
"""
import contextlib
import io
import os
import sys

HERE = os.path.dirname(os.path.abspath(__file__))
ROOT = os.path.normpath(os.path.join(HERE, ".."))
sys.path.insert(0, HERE)

with contextlib.redirect_stdout(io.StringIO()):
    import diagnose_zsched_persp as D


def load_frags(path):
    out = []
    with open(path) as f:
        for ln in f:
            p = ln.split()
            if len(p) >= 5:
                out.append((int(p[0]), int(p[1]), int(p[2]), int(p[3]), int(p[4], 16) & 0xFFFFFF))
    return out


def load_issue(path):
    out = []
    with open(path) as f:
        for ln in f:
            p = ln.split()
            if len(p) >= 7:
                out.append((int(p[0]), int(p[1]), int(p[2]), int(p[3]), int(p[4]), int(p[5]), int(p[6])))
    return out


def pct(ok, n):
    return 100.0 * ok / n if n else 0.0


def main(argv):
    trace_dir = os.path.join(ROOT, "sim", "traces", "rtl")
    frag_path = argv[1] if len(argv) > 1 else os.path.join(trace_dir, "zsched_frags.txt")
    issue_path = argv[2] if len(argv) > 2 else os.path.join(trace_dir, "zsched_issue.txt")

    with contextlib.redirect_stdout(io.StringIO()):
        _draw_idxs, _tris, _fb, _owner, _emitted, _accepted, model = D.render("zsched")
    frags = load_frags(frag_path)
    issue = load_issue(issue_path)
    n = min(len(model), len(frags), len(issue))

    by_ep = {}
    coord_miss = z_miss = 0
    for i in range(n):
        me = model[i]
        hwf = frags[i]
        hwi = issue[i]
        ep = hwf[0]
        st = by_ep.setdefault(ep, {
            "n": 0, "color": 0, "u": 0, "v": 0, "uv": 0,
            "u_ge512": 0, "v_ge512": 0,
        })
        st["n"] += 1
        if me[:3] != hwf[:3]:
            coord_miss += 1
        if abs(me[3] - hwf[3]) > 256:
            z_miss += 1
        if (me[4] & 0xFFFFFF) != hwf[4]:
            st["color"] += 1
        if me[5] != hwi[4]:
            st["u"] += 1
        if me[6] != hwi[5]:
            st["v"] += 1
        if me[5] != hwi[4] or me[6] != hwi[5]:
            st["uv"] += 1
        if hwi[4] >= 512:
            st["u_ge512"] += 1
        if hwi[5] >= 512:
            st["v_ge512"] += 1

    print(f"[uv] model={len(model)} frags={len(frags)} issue={len(issue)} compared={n} coord_miss={coord_miss} z_gt256={z_miss}")
    for ep in sorted(by_ep):
        st = by_ep[ep]
        n_ep = st["n"]
        u_ok = n_ep - st["u"]
        v_ok = n_ep - st["v"]
        uv_ok = n_ep - st["uv"]
        c_ok = n_ep - st["color"]
        print(
            f"[uv] e{ep}: n={n_ep} "
            f"color_ok={c_ok}/{n_ep} ({pct(c_ok,n_ep):.2f}%) "
            f"u_ok={u_ok}/{n_ep} ({pct(u_ok,n_ep):.2f}%) "
            f"v_ok={v_ok}/{n_ep} ({pct(v_ok,n_ep):.2f}%) "
            f"uv_ok={uv_ok}/{n_ep} ({pct(uv_ok,n_ep):.2f}%) "
            f"rtl_u_ge512={st['u_ge512']} rtl_v_ge512={st['v_ge512']}"
        )


if __name__ == "__main__":
    raise SystemExit(main(sys.argv))
