"""재생성 실험 갤러리 — 원본 ↔ 다시 찍은 것, 감독 판단, 재판정.

보여주는 것
  ① 수정 전(선정본) ↔ 다시 찍은 것 좌우 대조
  ② 두 심판이 선정본에 남긴 하드 위반
  ③ 감독(Opus)이 **채택한 결함 / 기각한 결함** 과 그 이유
  ④ 감독이 저작한 교정절, 그리고 상류(브리프) 수정 지목
  ⑤ 재판정 — 두 심판 × 정순·역순 4표
"""
from __future__ import annotations

import html
import json
import re
import sys
from pathlib import Path

ROOT = Path(__file__).resolve().parent.parent
PROJ = "e716bafb-24bb-42b7-aea0-fdb383844ee8"
EPI = "d6a9aa85-b75e-400c-980c-4ee7e876a15b"
RECIPE_WEB = f"/projects/{PROJ}/images/{EPI}/scene/recipe"
JUDGE_LABEL = {"claude-opus": "Opus 5", "gpt": "GPT-5.6 Sol"}

CSS = """
:root{--bg:#101319;--card:#191d26;--line:#2b313d;--fg:#e7eaf0;--dim:#98a1b3;
--win:#3ddc84;--lose:#ff6b6b;--warn:#ffa94d;--info:#74c0fc}
*{box-sizing:border-box}
body{margin:0;background:var(--bg);color:var(--fg);
font:14px/1.65 -apple-system,BlinkMacSystemFont,"Apple SD Gothic Neo",sans-serif}
header{position:sticky;top:0;z-index:9;background:#0b0d12ee;backdrop-filter:blur(8px);
border-bottom:1px solid var(--line);padding:14px 20px}
h1{margin:0 0 6px;font-size:17px}
.sum{color:var(--dim);font-size:13px}.sum b{color:var(--fg)}
.filters{margin-top:10px;display:flex;gap:8px;flex-wrap:wrap}
button{background:var(--card);color:var(--fg);border:1px solid var(--line);
border-radius:999px;padding:5px 13px;cursor:pointer;font-size:12px}
button.on{background:var(--fg);color:#101319;font-weight:600}
main{padding:18px 20px 80px;max-width:1700px;margin:0 auto}
.still{background:var(--card);border:1px solid var(--line);border-radius:12px;
padding:16px;margin-bottom:22px}
.hd{display:flex;gap:10px;align-items:baseline;flex-wrap:wrap;margin-bottom:8px}
.hd .id{font-size:16px;font-weight:700}.hd .meta{color:var(--dim);font-size:12px}
.tag{border-radius:5px;padding:2px 9px;font-size:11px;font-weight:700}
.t-new{background:var(--win);color:#101319}
.t-keep{background:var(--lose);color:#fff}
.t-skip{background:var(--info);color:#101319}
.cmp{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.cmp img{width:100%;border-radius:8px;display:block;border:3px solid var(--line)}
.cmp .taken img{border-color:var(--win)}
figure{margin:0}figcaption{font-size:12.5px;margin-top:6px;font-weight:600}
.sec{font-size:11px;letter-spacing:.08em;color:var(--dim);text-transform:uppercase;
margin:16px 0 6px}
ul{margin:6px 0 0;padding-left:18px;font-size:13px}li{margin-bottom:4px}
.taken-li{color:#c8f7d4}.dism-li{color:var(--dim);text-decoration:line-through}
.box{font-size:13px;color:#c2cad8;background:#0e1117;border:1px solid var(--line);
border-radius:7px;padding:10px;margin-top:6px}
.box b{color:var(--fg)}
.up{border-color:var(--warn)}
pre{white-space:pre-wrap;background:#0b0d12;border:1px solid var(--line);
border-radius:7px;padding:10px;font-size:11.5px;color:#c8cfdc;overflow-x:auto}
details{margin-top:10px}summary{cursor:pointer;color:var(--dim);font-size:12px}
.vote{font-size:12.5px;color:#c2cad8;margin-top:6px}
@media(max-width:900px){.cmp{grid-template-columns:1fr}}
"""
JS = """
const b=[...document.querySelectorAll('button[data-f]')];
b.forEach(x=>x.onclick=()=>{b.forEach(y=>y.classList.toggle('on',y===x));
const f=x.dataset.f;document.querySelectorAll('.still').forEach(s=>{
s.style.display=(f==='all'||s.dataset.f===f)?'':'none';});});
"""


def key(s):
    m = re.findall(r"\d+", s)
    return (int(m[0]), int(m[1])) if len(m) >= 2 else (9999, 9999)


def esc(x):
    return html.escape(str(x or ""))


def main() -> None:
    src = Path(sys.argv[1])
    outdir = src.parent
    d = json.loads(src.read_text("utf-8"))
    items = sorted(d.items(), key=lambda kv: key(kv[0]))

    n_new = sum(1 for _, v in items if v.get("final_is_new"))
    n_keep = sum(1 for _, v in items
                 if v.get("remade") and not v.get("final_is_new"))
    n_skip = sum(1 for _, v in items if not v.get("remade"))

    P = ['<meta charset="utf-8">',
         "<title>중요 샷 재생성 — 감독 Opus</title>",
         f"<style>{CSS}</style>", "<header>",
         "<h1>중요 샷 재생성 — 지시는 Opus, 판정은 Opus + Sol 이중</h1>",
         f'<div class="sum">대상 <b>{len(items)}</b> · '
         f'다시 찍어 채택 <b>{n_new}</b> · '
         f'개악 판정으로 원본 유지 <b>{n_keep}</b> · '
         f'다시 찍지 않음 <b>{n_skip}</b></div>',
         '<div class="filters"><button data-f="all" class="on">전체</button>'
         '<button data-f="new">새것 채택</button>'
         '<button data-f="keep">개악 → 원본 유지</button>'
         '<button data-f="skip">다시 찍지 않음</button></div></header><main>']

    for stem, v in items:
        plan = v.get("plan") or {}
        if v.get("final_is_new"):
            flag, badge = "new", '<span class="tag t-new">새것 채택</span>'
        elif v.get("remade"):
            flag, badge = "keep", '<span class="tag t-keep">개악 판정 → 원본 유지</span>'
        else:
            flag, badge = "skip", '<span class="tag t-skip">다시 찍지 않음</span>'

        rj = v.get("rejudge")
        vote = (f'{rj["new_votes"]}/{rj["total"]}표' if rj else "—")
        P.append(f'<section class="still" data-f="{flag}">')
        P.append(f'<div class="hd"><span class="id">{esc(stem)}</span>'
                 f'<span class="meta">선정 후보 {esc(v.get("selected_roll"))} · '
                 f'심판이 남긴 위반 {len(v.get("faults_in") or [])}건 · '
                 f'재판정 {vote}</span>{badge}</div>')

        if v.get("remade") and v.get("new"):
            newp = Path(v["new"]).name
            tk_o = " taken" if not v.get("final_is_new") else ""
            tk_n = " taken" if v.get("final_is_new") else ""
            P.append('<div class="cmp">'
                     f'<figure class="a{tk_o}"><img loading="lazy" '
                     f'src="{RECIPE_WEB}/{stem}_'
                     f'{str(v["selected_roll"]).lower()}.png">'
                     f'<figcaption>수정 전 — 선정본'
                     + ("  ← 채택" if not v.get("final_is_new") else "")
                     + "</figcaption></figure>"
                     f'<figure class="b{tk_n}"><img loading="lazy" '
                     f'src="remake/{newp}">'
                     f'<figcaption>다시 찍은 것'
                     + ("  ← 채택" if v.get("final_is_new") else "")
                     + "</figcaption></figure></div>")
        else:
            P.append(f'<div class="cmp"><figure><img loading="lazy" '
                     f'src="{RECIPE_WEB}/{stem}_'
                     f'{str(v["selected_roll"]).lower()}.png">'
                     f'<figcaption>선정본 (다시 찍지 않음)</figcaption>'
                     f'</figure></div>')

        P.append('<div class="sec">심판이 선정본에 남긴 하드 위반</div><ul>')
        for f in v.get("faults_in") or []:
            P.append(f"<li>{esc(f)}</li>")
        P.append("</ul>")

        P.append('<div class="sec">감독(Opus) 판단</div>')
        if plan.get("faults_taken"):
            P.append("<ul>" + "".join(
                f'<li class="taken-li">채택 — {esc(x)}</li>'
                for x in plan["faults_taken"]) + "</ul>")
        if plan.get("faults_dismissed"):
            P.append("<ul>" + "".join(
                f'<li class="dism-li">기각 — {esc(x)}</li>'
                for x in plan["faults_dismissed"]) + "</ul>")
        P.append(f'<div class="box"><b>이유</b> {esc(plan.get("reason_ko"))}</div>')
        if (plan.get("upstream_fix_ko") or "").strip() not in ("", "해당 없음"):
            P.append(f'<div class="box up"><b>★상류(브리프) 수정 지목</b> '
                     f'{esc(plan["upstream_fix_ko"])}</div>')

        if rj:
            rows = []
            for m, dd in rj["detail"].items():
                nm = JUDGE_LABEL.get(m, m)
                for tag, k in (("정순", "forward"), ("역순", "reverse")):
                    who = ({"A": "원본", "B": "새것"} if tag == "정순"
                           else {"A": "새것", "B": "원본"})
                    for c in dd[k]["verdicts"]:
                        rows.append(f'{nm} · {tag} · {who[c["label"]]} '
                                    f'{c["score"]}점 — {esc(c["verdict_ko"])}')
            P.append(f'<div class="vote"><b>재판정</b> 새것 '
                     f'{rj["new_votes"]}/{rj["total"]}표<br>'
                     + "<br>".join(rows) + "</div>")

        if plan.get("regen_clause_en"):
            P.append("<details><summary>감독이 저작한 교정절 (원 브리프에 덧붙여 "
                     "다시 찍음 — 결함 이미지는 참조로 주지 않음)</summary>"
                     f"<pre>{esc(plan['regen_clause_en'])}</pre></details>")
        P.append("</section>")

    P.append(f"</main><script>{JS}</script>")
    (outdir / "remake.html").write_text("\n".join(P), "utf-8")
    print(f"작성 완료: {outdir/'remake.html'}  "
          f"(대상 {len(items)} · 채택 {n_new} · 유지 {n_keep} · 미실행 {n_skip})")


if __name__ == "__main__":
    main()
