#!/usr/bin/env python3
"""s28 — floor_plan_prompt v10 (scale_guideline) live canary. 커밋 금지.

production 입력 조립(FloorPlanPromptStep._execute 재현)으로
run_floor_plan_prompt 를 selector "10" 으로 직접 호출 — 체크포인트 write 0.
대상: 옥탑 본건물 fp + 경찰서 전면 fp (규모 차가 큰 2건).
검증: ①scale_guideline 존재+근거 성격 ②기존 v6 필드 무결 ③t2i 평면 유지.
사용: backend/.venv/bin/python s28_fp_v10_canary.py
"""
import json
import sys
from pathlib import Path

BACKEND = Path("/Users/manta/Documents/Projects/TheRoad-I1/backend")
sys.path.insert(0, str(BACKEND))

PID = "1b4a975b-f4e5-46d7-8b28-876071d19907"
EID = "d5c3bffb-2ae7-4446-a17d-2221fea713b5"
CP = Path("/Users/manta/Documents/Projects/TheRoad-I1/projects") / PID / \
    "checkpoints" / "episodes" / EID
TARGET_FP_PREFIXES = ("fp_l04", "fp_l14")  # 옥탑 본건물 / 경찰서 전면
OUT = Path(__file__).parent / "plans" / "fp_v10_canary.json"


def load_cp(step):
    p = CP / step / "manifest.json"
    return json.loads(p.read_text(encoding="utf-8")) if p.exists() else None


def main():
    from app.core.steps.background_master_plan_step import _select_scenes_for_group
    from app.modules.llm.llm_client import call_structured
    from app.modules.pipeline.floor_plan_prompt import (
        build_fp_user_prompt,
        derive_fp_space_roles,
        run_floor_plan_prompt,
    )
    from app.services.visual_context_helper import build_visual_context_block

    plans_cp = load_cp("background_master_plan")
    scene_save_cp = load_cp("scene_save")
    shot_validator_cp = load_cp("shot_validator")
    shot_selection_cp = load_cp("shot_selection")
    rules_cp = load_cp("visual_world_rules")
    world_guide_cp = load_cp("world_guide")
    scene_director_cp = load_cp("scene_director")

    scene_primary = {}
    if scene_director_cp:
        for sc in (scene_director_cp.get("data", {}) or {}).get("scenes", []) or []:
            si, primary = sc.get("scene_index"), sc.get("primary_location", "") or ""
            if si is not None and primary:
                scene_primary[int(si)] = primary

    plans_map = ((plans_cp or {}).get("data", {}) or {}).get("plans", {}) or {}
    rules_text = build_visual_context_block(
        world_guide_cp=world_guide_cp, visual_world_rules_cp=rules_cp)
    scene_segments = (
        ((scene_save_cp or {}).get("data", {}) or {}).get("segments", []) or [])

    results = {}
    for gid, entry in plans_map.items():
        if entry.get("status") != "ok":
            continue
        plan = entry.get("plan") or {}
        group_member_locs = {bg.get("loc_id") for bg in (plan.get("backgrounds") or [])}
        synthetic_group = {
            "group_id": gid,
            "members": [{"loc_id": loc, "label": ""} for loc in group_member_locs if loc],
        }
        scenes, _ = _select_scenes_for_group(
            synthetic_group, scene_segments, shot_validator_cp,
            shot_selection_cp, scene_primary=scene_primary)
        for fp in plan.get("floor_plans") or []:
            fp_id = fp["fp_id"]
            if not fp_id.startswith(TARGET_FP_PREFIXES):
                continue
            applied_bgs = [bg for bg in (plan.get("backgrounds") or [])
                           if fp_id in (bg.get("depends_on_fp") or [])]
            applied_shots = []
            for bg in applied_bgs:
                applied_shots.extend(bg.get("applies_to_shots") or [])
            up = build_fp_user_prompt(
                fp_spec=fp,
                applied_backgrounds=applied_bgs,
                applied_shots=list(dict.fromkeys(applied_shots)),
                scene_segments=scenes,
                visual_world_rules=rules_text,
                prompt_version="10",
                space_roles=derive_fp_space_roles(applied_bgs),
            )
            expected_bg_ids = {bg["bg_id"] for bg in applied_bgs if bg.get("bg_id")}
            print(f"[call] {fp_id} (bgs={sorted(expected_bg_ids)})", flush=True)
            from app.core.creator_corrections import project_corrections_block
            out = run_floor_plan_prompt(
                user_prompt=up,
                expected_fp_id=fp_id,
                call_structured_fn=call_structured,
                expected_bg_ids=expected_bg_ids,
                prompt_version="10",
                creator_corrections_block=project_corrections_block(PID),
            )
            results[fp_id] = out
            print(f"  scale_guideline: {out['scale_guideline']}", flush=True)
            print(f"  (v6 필드 무결: numbered={len(out['numbered_elements'])} "
                  f"cams={len(out['camera_recommendations'])} "
                  f"t2i_len={len(out['t2i_prompt'])})", flush=True)

    OUT.write_text(json.dumps(results, ensure_ascii=False, indent=1),
                   encoding="utf-8")
    print(f"[saved] {OUT} ({len(results)} fps)", flush=True)
    assert results, "대상 fp 를 찾지 못함"


if __name__ == "__main__":
    main()
