#!/usr/bin/env python3
"""임시 실험 4 — 초경량 레이아웃 콘티 → 4분할 실사 → 사실화 (v3).

사용자 가설: 콘티 기반이 구도는 최고인데, 상세 연필 콘티의 질감이 실사를
오염 → 콘티를 '레이아웃만 아는 초경량 라인 스케치'로 낮추면 구도 제어와
실사 질감을 동시에 얻을 것.

체인: ①i2 — 2×2 레이아웃 전용 콘티 1장(음영·질감·묘사 0, 얇은 윤곽선
+배치+크기·깊이만) → ②등분 크롭 → ③nb2 — 4분할 실사 1장(참조=경량
패널 4+플레이트 1, 텍스트 계약 동일) → ④등분 크롭 → ⑤패널별 사실화
i2i. 산출: quad3_conti.png / quad3_s12.png / quad3_refined_*.png.
"""
import sys
from pathlib import Path

HERE = Path(__file__).parent
sys.path.insert(0, str(HERE))
import forest_lib as F  # noqa: E402
import s35_fullrun as R  # noqa: E402
import s37_rooftop_rebuild as W  # noqa: E402
import s34_stillrun as S  # noqa: E402
import x_quad_refine as REFINE  # noqa: E402

TAGS = ["S12sh11", "S12sh18", "S12sh21", "S14sh5"]
CONTI = W.OUT / "quad3_conti.png"
QUAD = W.OUT / "quad3_s12.png"

plan = F.load_plan(W.PLAN)
plan35 = W._s35()
mv = W._movement(plan35)
gmap = {g["key"]: g for g in plan35["groups"]}
place_en = gmap[W.INT_GROUP]["place_en"]

tag2plate = {}
for p_ in plan["int_plates"]:
    for t in p_["covers"]:
        tag2plate[t] = W.OUT / f"plate_{p_['key']}.png"


def panel_lines(include_time=True):
    lines = []
    for i, tag in enumerate(TAGS, 1):
        s = R.SHOT[R._key(tag)]
        m = mv.get(tag, {})
        fix = plan.get("pose_fix", {}).get(tag) or {}
        movement = fix.get("movement_en") or m.get("movement", "")
        figures = fix.get("figures_en") or m.get("figures", "")
        carried = fix.get("carried_en") or (plan.get("int_cont", {})
                                            .get(tag, {})
                                            .get("carried_en", ""))
        line = f"PANEL {i} ({tag})"
        if include_time:
            line += f" — TIME OF DAY (lock): {S._time_of(tag)}."
        line += (f"\n  SHOT TEXT (authoritative, Korean):"
                 f" {S._soften(s['desc'])}")
        if movement:
            line += f"\n  MOVEMENT (follow exactly): {S._soften(movement)}"
        if figures:
            line += ("\n  FIGURES — size & depth (follow exactly): "
                     + S._soften(figures))
        if carried:
            line += ("\n  CARRIED STATE (persist exactly across panels): "
                     + S._soften(carried))
        lines.append(line)
    return lines


pose_clauses = []
for it in plan.get("pose_canon", []):
    if any(t in it["shots"] for t in TAGS):
        pose_clauses.append(
            "IMMOBILE CHARACTER POSE — CANONICAL (identical wherever this"
            " character appears in ANY panel; on any conflict THIS POSE"
            " WINS): " + S._soften(it["pose_en"]))

# ── ① 초경량 레이아웃 콘티 (i2) ──
LIGHT_STYLE = "\n".join([
    "STYLE — LAYOUT-ONLY THUMBNAIL SKETCH: the lightest possible",
    "director's layout drawing. THIN, CLEAN, UNIFORM PENCIL CONTOUR",
    "LINES ONLY on pure white paper. Absolutely NO shading, NO tone, NO",
    "hatching, NO texture, NO grayscale fill, NO light-and-shadow, NO",
    "facial features beyond a bare head outline, NO clothing detail, NO",
    "material rendering. Each panel contains ONLY: the camera framing,",
    "each figure as a simple correct-proportion human contour in its",
    "exact pose and screen position/size, and the few major set masses",
    "(bed, door, wall, curtain, window) as plain outline boxes/shapes.",
    "It must read as a quick layout guide, never as a finished drawing.",
])
conti_prompt = "\n\n".join([
    "Draw ONE storyboard layout sheet: 4 panels made by ONE vertical"
    " cut at exactly 50% of the width and ONE horizontal cut at exactly"
    " 50% of the height — a 2x2 grid, each panel exactly one quarter of"
    " the image, separated only by thin straight black gutter lines.",
    LIGHT_STYLE,
    f"THE LOCATION (same in all panels): {place_en}",
    "\n".join(pose_clauses) if pose_clauses else "",
    "PANELS (one shot per panel, Korean shot text):",
    "\n".join(panel_lines(include_time=False)),
    "ABSOLUTELY NO TEXT anywhere: the ONLY allowed marking is a small"
    " shot number digit (1, 2, 3, 4) in a corner INSIDE each panel."
    " The grid fills the entire image edge-to-edge.",
])
F.img_gpt("x_quad3_conti", conti_prompt, refs=None, size="1024x1024",
          out_path=CONTI)
print("conti:", CONTI)

# ── ② 콘티 등분 크롭 ──
from PIL import Image  # noqa: E402
im = Image.open(CONTI).convert("RGB")
WIDTH, HEIGHT = im.size
boxes = [(0, 0, WIDTH // 2, HEIGHT // 2),
         (WIDTH // 2, 0, WIDTH, HEIGHT // 2),
         (0, HEIGHT // 2, WIDTH // 2, HEIGHT),
         (WIDTH // 2, HEIGHT // 2, WIDTH, HEIGHT)]
conti_panels = []
for tag, box in zip(TAGS, boxes):
    p = W.OUT / f"quad3_conti_{tag}.png"
    im.crop((box[0] + 3, box[1] + 3, box[2] - 3, box[3] - 3)).save(p)
    conti_panels.append(p)
    print("conti crop:", p.name)

# ── ③ 4분할 실사 (nb2, 참조=경량 콘티 4+플레이트 1) ──
refs = []
for i, (tag, p) in enumerate(zip(TAGS, conti_panels), 1):
    refs.append((f"LAYOUT SKETCH for PANEL {i} — a bare thin-line layout"
                 " guide, a REFERENCE ONLY: take from it ONLY the camera"
                 " framing, figure placement, pose and size/depth order"
                 " of that panel. It carries ZERO visual style — every"
                 " texture, material, light and all realism come from"
                 " the text and the photographic reference. Never let"
                 " any line-drawing quality leak into the output.", p))
plates = []
for tag in TAGS:
    p = tag2plate[tag]
    if p not in plates:
        plates.append(p)
for p in plates:
    refs.append((W.PLATE_STILL_LABEL, p))

quad_prompt = "\n\n".join([
    "Create ONE image split into 4 photorealistic live-action film"
    " stills: 4 panels made by ONE vertical cut at exactly 50% of the"
    " width and ONE horizontal cut at exactly 50% of the height — a 2x2"
    " grid, each panel exactly one quarter of the image, separated only"
    " by thin straight black gutter lines at those exact positions."
    " Panels are numbered 1 (top-left), 2 (top-right), 3 (bottom-left),"
    " 4 (bottom-right). Every panel is a FINAL photorealistic film"
    " still, as if captured on a real cinema camera on a real physical"
    " set — contemporary South Korea, 2026; all people are Korean"
    " unless stated. The attached LAYOUT SKETCHES are composition"
    " guides only and must leave NO stylistic trace in the image.",
    f"LOCATION (lock, same interior in all panels): {place_en} The"
    " attached LOCATION PHOTOGRAPH shows the exact place.",
    "PANELS ARE CHRONOLOGICAL — CONTINUE THE ACTION: each panel starts"
    " from the previous panel's end state (each person's position, pose,"
    " held objects, and the state of the room), advancing only what its"
    " shot text says. The SAME single location, its materials, fixed"
    " features and wear are identical across panels.",
    "\n".join(pose_clauses) if pose_clauses else "",
    S.REALIZE_STILL,
    "PANELS (one shot per panel):",
    "\n".join(panel_lines(include_time=True)),
    "No text, captions, watermarks or annotations anywhere in any"
    " panel.",
])
F.img_nb2("x_quad3_s12", quad_prompt, refs, aspect_ratio="1:1",
          out_path=QUAD)
print("quad:", QUAD)

# ── ④/⑤ 크롭 + 사실화 ──
im = Image.open(QUAD).convert("RGB")
WIDTH, HEIGHT = im.size
boxes = [(0, 0, WIDTH // 2, HEIGHT // 2),
         (WIDTH // 2, 0, WIDTH, HEIGHT // 2),
         (0, HEIGHT // 2, WIDTH // 2, HEIGHT),
         (WIDTH // 2, HEIGHT // 2, WIDTH, HEIGHT)]
for tag, box in zip(TAGS, boxes):
    p = W.OUT / f"quad3_panel_{tag}.png"
    im.crop((box[0] + 4, box[1] + 4, box[2] - 4, box[3] - 4)).save(p)
    out = W.OUT / f"quad3_refined_{tag}.png"
    F.img_nb2(f"x_quad3_refine_{tag}", REFINE.PROMPT,
              [(REFINE.REF_LABEL, p)], aspect_ratio="1:1", out_path=out)
    print("refined:", out.name)
print("DONE")
