"""참조 획득 **사람 비교 화면**. ★판을 차릴 뿐 판정하지 않는다. 유료 0.

대상 하나마다 **나란히** 놓는다 —

    원문 근거        어디서 이 대상이 나왔나
    보낸 질의        실제로 검색에 나간 말
    받은 후보 3~5장  **그림으로**
    종류 판정        심판이 후보마다 무엇이라 했나 (종류·가시성만)
    고른 참조        어느 것을 왜 골랐나

★VLM 은 **종류와 가시성**만 봤다. 시대·국가·제조사·모델·고증 정확성·좋고
나쁨은 **안 물었다** — 그건 사람 몫이다.

    python tools/grounding_audit/ref_review.py <j_ref.json> <out.html>
"""
from __future__ import annotations

import html
import json
import sys
from pathlib import Path
from typing import Any, Dict, List, Sequence


def _e(x: Any) -> str:
    return html.escape(str(x if x is not None else ""))


STATUS_LABEL = {
    "selected": "골랐다",
    "no_match_after_retry": "두 라운드 다 봤는데 종류가 맞는 것이 없다",
    "retryable": "다 못 봤다 (없다는 뜻이 아니다)",
}


def _verdict_for(rd: Dict[str, Any], index: int) -> str:
    """후보 하나에 심판들이 뭐라 했나. ★해석 안 하고 **그대로** 적는다."""
    out = []
    for row in rd.get("eligibility") or ():
        if int(row.get("index") or 0) != index:
            continue
        for judge, v in sorted((row.get("by_judge") or {}).items()):
            if not v:
                out.append(f"{judge}: 답 없음")
                continue
            out.append(f"{judge}: 종류 {v.get('object_type_match')} · "
                       f"보임 {v.get('visible')}")
    return " / ".join(out) or "—"


def _cands(rd: Dict[str, Any], chosen_path: str) -> str:
    got = rd.get("downloaded_candidates") or []
    if not got:
        return ('<div class=noimg>이 라운드는 받은 사진이 <b>0장</b>입니다 — '
                '검색이 아무것도 못 돌려줬습니다</div>')
    cells = []
    for c in got:
        pick = " picked" if c["path"] == chosen_path else ""
        cells.append(f"""
<figure class="cand{pick}">
  <img loading=lazy src="/{_e(c['path'])}" alt="후보 {_e(c['index'])}">
  <figcaption>
    <b>{_e(c['index'])}{' · 고른 것' if pick else ''}</b>
    <div class=v>{_e(_verdict_for(rd, int(c['index'])))}</div>
    <div class=cap>{_e(c.get('caption'))}</div>
    <a href="{_e(c.get('source_website_url') or c['url'])}"
       target=_blank rel=noopener>출처</a>
  </figcaption>
</figure>""")
    return f'<div class=cands>{"".join(cells)}</div>'


def _rounds(rec: Dict[str, Any]) -> str:
    out = []
    for rd in rec.get("rounds") or ():
        q = rd.get("queries") or []
        flat = [x for g in q for x in (g if isinstance(g, list) else [g])]
        out.append(f"""
<section class=round>
  <h4>라운드 {_e(rd['round_no'])}
    <span class=hint>받음 {_e(rd['received'])} · 판정 {_e(rd['downloaded'])}
      · 중복 {_e(rd['duplicate'])}</span></h4>
  <div class=q><b>보낸 질의</b>
    <ul>{''.join(f'<li><code>{_e(x)}</code></li>' for x in flat)
         or '<li class=hint>질의가 하나도 안 나갔습니다</li>'}</ul></div>
  {_cands(rd, rec.get('chosen_path') or '')}
  <p class=why>{_e(rd.get('decision', {}).get('why'))}</p>
</section>""")
    return "".join(out)


def render(doc: Dict[str, Any]) -> str:
    recs = doc.get("records") or []
    cards = []
    for rec in recs:
        t = rec.get("target") or {}
        st = str(rec.get("status"))
        quotes = "".join(
            f"<li>{_e(o.get('source_quote'))}</li>"
            for o in (t.get("occurrences") or ()))
        chosen = rec.get("chosen_path") or ""
        cards.append(f"""
<article class="row {'ok' if st == 'selected' else 'no'}">
  <header>
    <span class=own>{_e(t.get('owner_type'))}</span>
    <b>{_e(t.get('surface_form'))}</b>
    <span class=id>{_e(t.get('final_id') or t.get('local_id'))}</span>
    <span class=badge>{_e(STATUS_LABEL.get(st, st))}</span>
  </header>
  <div class=top>
    <section>
      <h4>원문 근거</h4><ul>{quotes or '<li>—</li>'}</ul>
      <h4>겉모습 (모델이 적은 것)</h4>
      <p class=brief>{_e(t.get('visual_brief'))}</p>
      <h4>찾을 낱말</h4>
      <p class=hint>{_e(', '.join(t.get('terms_native') or []))}</p>
    </section>
    <section>
      <h4>고른 참조</h4>
      {f'<img class=chosen loading=lazy src="/{_e(chosen)}">' if chosen
       else '<div class=noimg>고른 것이 없습니다</div>'}
    </section>
  </div>
  {_rounds(rec)}
</article>""")

    n_ok = sum(1 for r in recs if r.get("status") == "selected")
    return f"""<meta charset="utf-8">
<title>참조 획득 — 사람 검토</title>
<style>
 body{{font:14px/1.65 system-ui,-apple-system,sans-serif;margin:0;
   background:#f6f6f7;color:#1a1a1a}}
 .wrap{{max-width:1180px;margin:0 auto;padding:24px}}
 h1{{font-size:21px;margin:0 0 4px}}
 .note{{background:#fff8e1;border:1px solid #f0d98c;padding:12px 14px;
   border-radius:8px;margin:14px 0;font-size:13px}}
 table{{border-collapse:collapse;font-size:13px;margin:12px 0}}
 td,th{{border:1px solid #e3e3e6;padding:5px 11px;text-align:left}}
 .row{{background:#fff;border:1px solid #e3e3e6;border-radius:10px;
   margin:16px 0;overflow:hidden}}
 .row.ok{{border-left:4px solid #2e7d32}} .row.no{{border-left:4px solid #ef6c00}}
 header{{display:flex;gap:10px;align-items:center;flex-wrap:wrap;
   padding:10px 14px;background:#fafafa;border-bottom:1px solid #eee}}
 .own{{font-size:11px;background:#eceff1;padding:2px 8px;border-radius:99px}}
 .id{{font-family:ui-monospace,monospace;font-size:11px;color:#777}}
 .badge{{margin-left:auto;font-size:12px;color:#555}}
 .top{{display:grid;grid-template-columns:1fr 340px;gap:0}}
 section{{padding:10px 14px;border-right:1px solid #f2f2f2}}
 h4{{margin:8px 0 4px;font-size:12px;color:#666;font-weight:600}}
 ul{{margin:0;padding-left:16px}} li{{margin:2px 0}}
 .hint{{color:#888;font-size:11px}}
 .brief{{margin:0;font-size:13px;color:#333}}
 .round{{border-top:1px solid #f0f0f0;border-right:0;background:#fcfcfd}}
 .cands{{display:flex;gap:10px;flex-wrap:wrap;margin:6px 0}}
 .cand{{margin:0;width:190px;background:#fff;border:1px solid #e6e6e9;
   border-radius:8px;overflow:hidden}}
 .cand.picked{{border:2px solid #2e7d32}}
 .cand img{{width:100%;display:block;background:#eee}}
 figcaption{{padding:6px 8px;font-size:11px}}
 .v{{color:#444;margin:3px 0}} .cap{{color:#888;margin:3px 0}}
 img.chosen{{width:100%;max-width:320px;border-radius:8px;background:#eee}}
 .noimg{{font-size:12px;color:#999;padding:12px;background:#fafafa;
   border:1px dashed #ddd;border-radius:8px;max-width:320px}}
 .why{{margin:6px 0 0;font-size:12px;color:#555}}
 code{{background:#eef;padding:1px 5px;border-radius:4px;font-size:11px}}
</style>
<div class=wrap>
<h1>참조 획득 — 사람 검토</h1>
<div class=note>
 <b>★이 화면은 판정하지 않습니다.</b> VLM 이 본 것은 <b>「우리가 찾던 종류가
 맞나」와 「또렷이 보이나」 둘뿐</b>입니다. 시대·국가·제조사·모델·고증
 정확성·좋고 나쁨은 <b>묻지 않았습니다</b>.<br>
 <b>고증이 맞는지 · 이 참조가 쓸 만한지는 사람이 봅니다.</b>
</div>
<table>
 <tr><th>대상</th><td>{len(recs)}</td>
     <th>고름</th><td>{n_ok}</td>
     <th>못 고름</th><td>{len(recs) - n_ok}</td>
     <th>승인 논리 상한</th><td>{_e(doc.get('approved_logical'))}</td></tr>
</table>
{''.join(cards)}
</div>"""


def main() -> int:
    if len(sys.argv) < 3:
        print(__doc__)
        return 2
    doc = json.loads(Path(sys.argv[1]).read_text(encoding="utf-8"))
    out = Path(sys.argv[2])
    out.write_text(render(doc), encoding="utf-8")
    print(f"■ 적었다: {out}")
    print("  ★이 화면은 **판을 차릴 뿐** 판정하지 않는다.")
    return 0


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