#!/usr/bin/env python3
"""The real metric: per-question English-baseline → Spanish+sandwich
transition. Absolute es grounding % is uninterpretable on an
adversarial bench; what the sandwich *costs* is the transition.

  usage: es_delta.py <en_baseline.jsonl> <es_sandwich.jsonl>

Joins on the en↔es map. Buckets each question:
  PRESERVED   en grounded (S/H)  & es grounded
  DOWNGRADE   en STRICT          & es HYBRID            (partial cost)
  LOST        en grounded        & es UNGROUNDED        (the real cost)
  N/A         en UNGROUNDED                              (sandwich not at fault)
  GAINED      en UNGROUNDED      & es grounded           (noise/curio)
Then cross-tabs LOST vs the round-trip bucket — does drift predict
the *loss* transition (even though it didn't predict absolute %)?
"""
from __future__ import annotations

import json
import sys
from collections import Counter
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
RES = ROOT / "bench" / "qa_results"
GROUNDED = {"STRICT", "HYBRID"}


def load(p):
    return [json.loads(x) for x in Path(p).read_text().splitlines() if x.strip()]


def main() -> int:
    en_rows = load(sys.argv[1])
    es_rows = load(sys.argv[2])
    pairs = json.loads((ROOT / "bench" / "qa_questions_es_map.json").read_text())
    rt = {r["es"]: r["bucket"] for r in
          json.loads((RES / "es_roundtrip.json").read_text())}
    en_am = {r["question"]: r.get("audit_mode") for r in en_rows}
    es_am = {r["question"]: r.get("audit_mode") for r in es_rows}

    cls = Counter()
    lost_by_bucket = Counter()
    lost_list, downgrade_list = [], []
    for p in pairs:
        en, es = p["en"], p["es"]
        a, b = en_am.get(en), es_am.get(es)
        if a is None or b is None:
            cls["MISSING"] += 1
            continue
        if a not in GROUNDED:
            cls["N/A (en ungrounded)"] += 1
            if b in GROUNDED:
                cls["  └ of which GAINED"] += 1
            continue
        if b not in GROUNDED:
            cls["LOST"] += 1
            lost_by_bucket[rt.get(es, "?")] += 1
            lost_list.append((en, es, a, b))
        elif a == "STRICT" and b == "HYBRID":
            cls["DOWNGRADE (S→H)"] += 1
            downgrade_list.append((en, es))
        else:
            cls["PRESERVED"] += 1

    n = len(pairs)
    en_g = sum(1 for p in pairs if en_am.get(p["en"]) in GROUNDED)
    es_g = sum(1 for p in pairs if es_am.get(p["es"]) in GROUNDED)
    print(f"n={n}  EN-baseline grounded={en_g} ({en_g/n:.0%})  "
          f"ES+sandwich grounded={es_g} ({es_g/n:.0%})  "
          f"net Δ={es_g-en_g:+d}")
    print("\ntransition (only en-grounded questions can be 'LOST'):")
    for k, v in cls.most_common():
        print(f"  {k:<24} {v}")
    print("\nLOST × round-trip bucket (does drift predict the LOSS?):")
    for bk in ("CLEAN", "DRIFT", "COLLAPSE", "?"):
        if lost_by_bucket.get(bk):
            print(f"  {bk:<9} {lost_by_bucket[bk]}")
    print("\n-- LOST questions (en grounded, es+sandwich UNGROUNDED) --")
    for en, es, a, b in lost_list:
        print(f"  [{a}→{b}] en={en}\n            es={es}  rt={rt.get(es)}")
    return 0


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