#!/usr/bin/env python3
"""Round-trip drift analysis for #000056 (the pattern, deterministic).

For each bench pair: en --[opus-mt-en-es]--> es --[opus-mt-es-en]--> en'
The es→en leg is the SANDWICH'S ACTUAL edge-IN. If en' preserves the
content nouns of en, the sandwich feeds FTS5 the right terms and
grounding tracks the English baseline. If a content noun is lost
(Hamlet→"village", "New London"→"new London"), retrieval can't find
the article no matter how good Hermes is — the failure is upstream of
grounding, in named-entity-preserving MT.

Buckets by content-token recall of en' vs en (stopword-stripped):
  CLEAN     >= 0.80   COLLAPSE  < 0.40   DRIFT  otherwise
No Hermes, no network — offline + reproducible.
"""
from __future__ import annotations

import json
import re
import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
from arborist.qa.mt import OpusMTTranslator  # noqa: E402

_W = re.compile(r"[A-Za-z][A-Za-z0-9]*")
_STOP = set("the a an is are was were be of to in on at for with by from as "
            "and or what who where when why how which this that who whom did "
            "do does has have had can could would will who're were name named "
            "between play wrote write written who's".split())


def toks(s: str) -> set[str]:
    return {w.lower() for w in _W.findall(s) if w.lower() not in _STOP and len(w) > 1}


def main() -> int:
    pairs = json.loads((ROOT / "bench" / "qa_questions_es_map.json").read_text())
    tr = OpusMTTranslator()
    rows = []
    for p in pairs:
        en, es = p["en"], p["es"]
        back = tr.translate(es, "es", "en")  # the sandwich's edge-IN
        a, b = toks(en), toks(back)
        recall = round(len(a & b) / len(a), 2) if a else 1.0
        bucket = "CLEAN" if recall >= 0.80 else "COLLAPSE" if recall < 0.40 else "DRIFT"
        lost = sorted(a - b)
        rows.append({"en": en, "es": es, "back": back, "recall": recall,
                     "bucket": bucket, "lost_tokens": lost})
    out = ROOT / "bench" / "qa_results" / "es_roundtrip.json"
    out.write_text(json.dumps(rows, ensure_ascii=False, indent=2) + "\n")
    from collections import Counter
    c = Counter(r["bucket"] for r in rows)
    n = len(rows)
    print(f"n={n}  CLEAN={c['CLEAN']} ({c['CLEAN']/n:.0%})  "
          f"DRIFT={c['DRIFT']} ({c['DRIFT']/n:.0%})  "
          f"COLLAPSE={c['COLLAPSE']} ({c['COLLAPSE']/n:.0%})")
    print("\n-- COLLAPSE (named entity / key noun lost on round-trip) --")
    for r in rows:
        if r["bucket"] == "COLLAPSE":
            print(f"  en : {r['en']}\n  back: {r['back']}  lost={r['lost_tokens']}")
    print("\n-- a few CLEAN --")
    for r in [x for x in rows if x["bucket"] == "CLEAN"][:6]:
        print(f"  {r['en']}  ==~  {r['back']}")
    print(f"\nwrote {out}")
    return 0


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