"""컨트리로드 3판 최종 갤러리 — NAS 배포본.

이미지는 **원본 크기로 크게**, 샷마다 **설명**(씬 제목·대표 순간)을 붙인다.
쓰기: .venv/bin/python build_cr3_nas.py [출력디렉토리]
"""
from __future__ import annotations

import html
import json
import os
import shutil
import subprocess
import sys
from datetime import datetime
from pathlib import Path

PID = "91b9626e-83ee-4a85-9208-0c8e2d153a63"
EID = "e565764e-23fa-4991-a743-975fd8d061df"
ROOT = Path(__file__).resolve().parent.parent
CP = ROOT / "projects" / PID / "checkpoints" / "episodes" / EID
OUT = Path(sys.argv[1]) if len(sys.argv) > 1 else (
    ROOT / "artifact" / f"{datetime.now():%Y%m%d}_컨트리로드3판_최종")


def q(sql: str) -> list[list[str]]:
    out = subprocess.run(
        ["psql", "-h", "localhost", "-U", "theroad", "-d", "theroad",
         "-t", "-A", "-F", "\x1f", "-c", sql],
        capture_output=True, text=True,
        env={"PGPASSWORD": "theroad_dev_2026",
             "PATH": "/usr/bin:/bin:/usr/local/bin:/opt/homebrew/bin"})
    if out.returncode != 0:
        raise RuntimeError(out.stderr[:400])
    return [ln.split("\x1f") for ln in out.stdout.splitlines() if ln.strip()]


def main() -> None:
    scenes = (json.loads((CP / "scene_detail" / "manifest.json").read_text(
        encoding="utf-8")).get("data") or {}).get("scenes") or []
    desc: dict[tuple[int, int], dict] = {}
    for s in scenes:
        try:
            key = (int(s.get("scene_index")), int(s.get("_shot_index")))
        except (TypeError, ValueError):
            continue
        vs = s.get("t2i_variations") or [{}]
        desc[key] = {
            "heading": str(s.get("heading") or ""),
            "beat": str(s.get("beat_title") or ""),
            "moment": str(s.get("representative_moment") or ""),
            "camera": str((vs[0] or {}).get("camera_effect") or ""),
        }

    rows = q(
        "SELECT ss.scene_index, ss.shot_index, ia.file_path, "
        "coalesce(ia.generation_model,'') "
        "FROM scene_still ss JOIN image_asset ia ON ia.still_id = ss.id "
        f"WHERE ss.episode_id = '{EID}' AND ia.stage = 'scene_image' "
        "ORDER BY ss.scene_index, ss.shot_index;")
    print(f"스틸 {len(rows)}장")

    img_dir = OUT / "img"
    img_dir.mkdir(parents=True, exist_ok=True)
    parts = [
        '<meta charset="utf-8">',
        '<meta name="viewport" content="width=device-width,initial-scale=1">',
        "<title>컨트리로드 — 3판</title>",
        "<style>"
        "body{background:#0e0e10;color:#e8e8ea;margin:0;padding:24px 16px;"
        "font-family:system-ui,-apple-system,'Apple SD Gothic Neo',sans-serif;"
        "line-height:1.65}"
        "h1{font-size:22px;margin:0 0 4px}"
        ".sub{color:#8f8f97;font-size:13px;margin-bottom:28px}"
        ".shot{max-width:1536px;margin:0 auto 56px}"
        ".shot img{width:100%;height:auto;display:block;border-radius:8px;"
        "background:#000}"
        ".tag{font-size:13px;color:#7fb2ff;font-weight:600;margin-bottom:4px}"
        ".head{font-size:15px;color:#d8d8dd;margin-bottom:2px}"
        ".moment{font-size:15px;color:#b9b9c2;margin-top:10px}"
        ".meta{font-size:12px;color:#6f6f78;margin-top:6px}"
        "</style>",
        "<h1>컨트리로드 — 3판</h1>",
        f"<div class='sub'>{len(rows)}장 · gpt-image-2.5 조립 "
        f"(카메라 문안 통합, 변환 없음) · 검열은 grok → seedream · "
        f"{datetime.now():%Y-%m-%d %H:%M} KST</div>",
    ]

    for si, shi, fp, model in rows:
        src = ROOT / fp
        name = f"S{si}sh{shi}{src.suffix or '.png'}"
        if src.is_file():
            shutil.copy2(src, img_dir / name)
        d = desc.get((int(si), int(shi)), {})
        parts.append("<div class='shot'>")
        parts.append(f"<div class='tag'>S{si}sh{shi}</div>")
        if d.get("heading"):
            parts.append(f"<div class='head'>{html.escape(d['heading'])}"
                         + (f" · {html.escape(d['beat'])}" if d.get("beat")
                            else "") + "</div>")
        parts.append(f"<img loading='lazy' src='img/{html.escape(name)}'>")
        if d.get("moment"):
            parts.append(
                f"<div class='moment'>{html.escape(d['moment'])}</div>")
        bits = [x for x in (d.get("camera"), model) if x]
        if bits:
            parts.append(
                f"<div class='meta'>{html.escape(' · '.join(bits))}</div>")
        parts.append("</div>")

    (OUT / "index.html").write_text("\n".join(parts), encoding="utf-8")
    n = len(list(img_dir.glob("*")))
    print(f"이미지 {n}장 복사 · {OUT}/index.html")


if __name__ == "__main__":
    main()
