"""s9 — 5라운드(사용자 지시): LLM 프롬프트 저작 버드아이즈뷰 4종 교차 실험.

옥탑방 관련 모든 내용(그룹 멤버+전 샷 원문)을 취합해 **LLM 이 4개의 이미지
프롬프트를 직접 작성**(fp/도면 참조 없음 — 프롬프트 저작력 자체를 검증):
  1. 위에서 본 스케치 (완전 수직 아님 — 약 150도, 수직에서 ~30도 기울임) 순수 T2I
  2. 버드아이즈 뷰 — 1번 이미지를 참조(I2I)
  3. 버드아이즈 뷰 — 참조 없이 순수 T2I
  4. 스케치(1번과 같은 형태) — 3번 이미지를 참조(I2I)
산출: out/birdseye/{p1..p4}.png + plans/birdseye_prompts.json + birdseye.html
사용: .venv/bin/python s9_birdseye_prompts.py [--only prompts|images|html]
"""
import argparse
import html as _html
import json
import sys
from pathlib import Path

sys.path.insert(0, str(Path(__file__).parent))
import forest_lib as F  # noqa: E402

OUTB = F.OUT / "birdseye2"  # v2 (간결·중립 계약) — v1 은 out/birdseye/ 보존

GEN_SYSTEM = """You write text-to-image prompts for LOCATION REFERENCE ASSETS in film
pre-production. The place is one scouted real-world location: a building and its
grounds with connected indoor and outdoor parts — every specific comes from the
production data you receive (member descriptions + full shot contents). Extract
ONLY the permanent physical anatomy of the place from it.

Write FOUR ENGLISH image prompts. HARD STYLE RULES for every prompt:
- CONCISE. 60-110 words each. List what must be IN the image — nothing else.
- This is a NEUTRAL location document. NO storytelling, NO mood, NO atmosphere
  words, NO weather, NO time-of-day drama, NO lighting effects (no glow, no haze,
  no wet reflections), NO story props or states (no flyers, no vehicles, no lit
  windows). Plain even daylight. Cinematic dressing happens later in shots — never
  here.
- Include only PERMANENT physical elements grounded in the data (structures,
  levels, stairs, openings, fixed roof-level fixtures).
- Never expose interior rooms/furniture. No people, no animals, no text/letters/
  numbers/logos in the image.
- View: from high above at an oblique angle, tilted about 30 degrees from vertical
  (NOT straight down), so wall heights, the stair run and level differences read.
- Whole property in one view: any upper-level unit shell + its deck + fixtures,
  the building body below, any exterior stair route from ground to the top
  level, the ground entrance/approach spaces, small margin of neighbours.

The four prompts:
1. prompt_1_plan: a technical PLAN DRAWING in the exact drafting style of a clean
   architectural floor plan (thin dark outlines, flat colour fills, simple fixture
   symbols) but drawn with slight axonometric depth at that oblique angle. Pure
   text-to-image.
2. prompt_2_birdseye_from_plan: photorealistic bird's-eye of the same place;
   image-edit prompt — keep the attached drawing's layout, proportions and camera
   angle exactly; render real materials in plain daylight.
3. prompt_3_birdseye_pure: photorealistic bird's-eye, standalone text-to-image;
   the text alone carries the layout.
4. prompt_4_plan_from_birdseye: same technical plan-drawing form as prompt 1;
   image-edit prompt — redraw the attached photo in that drafting style, keeping
   layout and camera angle exactly.

Also output a faithful KOREAN translation of each prompt (for human review only;
the image model receives the English)."""

GEN_SCHEMA = {
    "type": "object",
    "properties": {
        "prompt_1_plan": {"type": "string"},
        "prompt_1_plan_ko": {"type": "string"},
        "prompt_2_birdseye_from_plan": {"type": "string"},
        "prompt_2_birdseye_from_plan_ko": {"type": "string"},
        "prompt_3_birdseye_pure": {"type": "string"},
        "prompt_3_birdseye_pure_ko": {"type": "string"},
        "prompt_4_plan_from_birdseye": {"type": "string"},
        "prompt_4_plan_from_birdseye_ko": {"type": "string"},
        "notes": {"type": "string",
                  "description": "what data grounded the layout choices"},
    },
    "required": ["prompt_1_plan", "prompt_1_plan_ko",
                 "prompt_2_birdseye_from_plan", "prompt_2_birdseye_from_plan_ko",
                 "prompt_3_birdseye_pure", "prompt_3_birdseye_pure_ko",
                 "prompt_4_plan_from_birdseye", "prompt_4_plan_from_birdseye_ko",
                 "notes"],
    "additionalProperties": False,
}


def gen_prompts(recon):
    members = F.members_block(recon["members"])
    shot_blocks = "\n\n".join(
        F.shot_block(k, s) for k, s in sorted(recon["shots"].items()))
    user = ("PLACE MEMBERS:\n" + members
            + "\n\nALL SHOTS AT THIS PLACE (full content):\n\n" + shot_blocks
            + "\n\nWrite the four prompts now.")
    out = F.llm("forest_birdseye_prompts_v2", GEN_SYSTEM, user, GEN_SCHEMA,
                model="gpt")
    F.save_plan("birdseye_prompts_v2", out)
    for k in ("prompt_1_plan", "prompt_2_birdseye_from_plan",
              "prompt_3_birdseye_pure", "prompt_4_plan_from_birdseye"):
        print(f"--- {k} ({len(out[k].split())} words)")
    return out


def images(p):
    OUTB.mkdir(parents=True, exist_ok=True)
    p1 = F.img_gpt("bird2_p1_plan", p["prompt_1_plan"], refs=None,
                   out_path=OUTB / "p1_plan_t2i.png")
    F.img_gpt("bird2_p2_from_plan", p["prompt_2_birdseye_from_plan"],
              refs=[p1], out_path=OUTB / "p2_birdseye_from_p1.png")
    p3 = F.img_gpt("bird2_p3_pure", p["prompt_3_birdseye_pure"], refs=None,
                   out_path=OUTB / "p3_birdseye_t2i.png")
    F.img_gpt("bird2_p4_from_birdseye", p["prompt_4_plan_from_birdseye"],
              refs=[p3], out_path=OUTB / "p4_plan_from_p3.png")


def build_html(p):
    def cell(fn, no, title, prompt_ko, prompt_en, ref=""):
        f = OUTB / fn
        det = (f"<details open><summary>프롬프트 (한국어)</summary>"
               f"<pre>{_html.escape(prompt_ko)}</pre></details>"
               f"<details><summary>영어 원문 (실제 T2I 입력)</summary>"
               f"<pre>{_html.escape(prompt_en)}</pre></details>")
        if not f.exists():
            return (f"<div class='cell'><h3>{no}. {_html.escape(title)}</h3>"
                    f"<div class='ref'>⏳ 생성 중… (완료되면 자동 표시)</div>{det}</div>")
        rel = f.relative_to(F.EXP)
        refline = f"<div class='ref'>참조 이미지: {ref}</div>" if ref else \
            "<div class='ref'>참조 없음 (순수 T2I)</div>"
        return (f"<div class='cell'><h3>{no}. {_html.escape(title)}</h3>{refline}"
                f"<a href='{rel}' target='_blank'><img src='{rel}'></a>{det}</div>")

    pending = any(not (OUTB / fn).exists() for fn in (
        "p1_plan_t2i.png", "p2_birdseye_from_p1.png",
        "p3_birdseye_t2i.png", "p4_plan_from_p3.png"))
    refresh = "<meta http-equiv='refresh' content='30'>" if pending else ""
    doc = f"""<meta charset='utf-8'>{refresh}<title>birdseye 4-prompt 교차 실험</title><style>
body{{font-family:sans-serif;background:#171717;color:#eee;margin:24px;max-width:1760px}}
.grid{{display:grid;grid-template-columns:1fr 1fr;gap:18px}}
.cell{{background:#222;padding:12px;border-radius:10px}}
.cell img{{width:100%;border-radius:6px}}
h1{{font-size:22px}} h3{{color:#fd9;margin:2px 0 6px}}
.ref{{color:#8ac;font-size:13px;margin-bottom:6px}}
pre{{white-space:pre-wrap;font-size:11px;color:#9c9;max-height:320px;overflow:auto;background:#1b1b1b;padding:8px}}
.guide{{background:#1e2430;padding:12px 16px;border-radius:8px;font-size:13px;line-height:1.6;margin-bottom:14px}}
</style>
<h1>버드아이즈뷰 4-프롬프트 교차 실험 v2 — 간결·중립(로케이션 문서) 계약</h1>
<div class='guide'>수정 반영: <b>스케치=fp 도면 언어+약간의 입체감(수직에서 ~30° 기울임)</b>,
프롬프트=<b>간결(60-110단어)·담을 내용만</b> — 영화적 무드/조명/이야기 소품 금지(중립 주광,
섭외 로케이션 문서). 영화적 표현은 실제 샷 생성 때만. 경로 비교:
<b>①도면(T2I) → ②버드아이(①참조)</b> vs <b>③버드아이(순수 T2I) → ④도면(③참조)</b>.</div>
<div class='grid'>
{cell('p1_plan_t2i.png', 1, 'fp형 도면+입체감 (순수 T2I)', p['prompt_1_plan_ko'], p['prompt_1_plan'])}
{cell('p2_birdseye_from_p1.png', 2, '버드아이즈 뷰 (①번 도면 참조 I2I)', p['prompt_2_birdseye_from_plan_ko'], p['prompt_2_birdseye_from_plan'], '① p1_plan_t2i.png')}
{cell('p3_birdseye_t2i.png', 3, '버드아이즈 뷰 (참조 없이 순수 프롬프트)', p['prompt_3_birdseye_pure_ko'], p['prompt_3_birdseye_pure'])}
{cell('p4_plan_from_p3.png', 4, 'fp형 도면 (①과 같은 형태, ③번 참조 I2I)', p['prompt_4_plan_from_birdseye_ko'], p['prompt_4_plan_from_birdseye'], '③ p3_birdseye_t2i.png')}
</div>
<details style='margin-top:16px'><summary>프롬프트 저작 LLM 의 grounding notes</summary>
<pre>{_html.escape(p.get('notes', ''))}</pre></details>
"""
    (F.EXP / "birdseye.html").write_text(doc)
    print(f"page -> {F.EXP / 'birdseye.html'}")


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--only", default="all", choices=["all", "prompts", "images",
                                                      "html"])
    args = ap.parse_args()
    recon = F.load_recon()
    if args.only in ("all", "prompts"):
        p = gen_prompts(recon)
    else:
        p = F.load_plan("birdseye_prompts_v2")
    if args.only in ("all", "images"):
        images(p)
    if args.only in ("all", "html"):
        build_html(p)
    F.runlog({"kind": "stage", "stage": "s9_birdseye", "done": args.only})


if __name__ == "__main__":
    main()
