#!/usr/bin/env python3
"""W-M canary 체크포인트 검증 — 커밋 금지.

background_render cp 에서:
  1. 야외 체인 plate: ref = aerial + (prev) 만, 총 ≤2 — 4장 동시 소멸 확인
  2. 실내 plate(interior_room): building_anchor/aerial 외부 ref 0
  3. L09B01 류(실내 분류 loc 의 외관 plate): anchor 유지 확인
  4. stage_chain 필드/순서(order_source)/diag
  5. DB input_image_ids 실측(aerial UUID 1순위 + prev UUID)
"""
import json
from pathlib import Path

import psycopg2

PID = "b0ad5c18-5140-4022-a2b0-805de0e5a385"
EID = "0d30302a-51c8-4ac9-98e2-6cd9180512bf"
ROOT = Path("/Users/manta/Documents/Projects/TheRoad-I1")
CP = ROOT / "projects" / PID / "checkpoints" / "episodes" / EID

cp = json.loads((CP / "background_render" / "manifest.json").read_text())
data = cp["data"]
groups = data["groups"]

print("═══ 1. location_aerials diag ═══")
for gid, d in sorted((data.get("location_aerials") or {}).items()):
    sc = d.get("stage_chain") or {}
    print(f"  {gid}: status={d.get('status')} cached={d.get('cached')} "
          f"fp_used={d.get('building_fp_used')} ver={d.get('prompt_version')}")
    if sc:
        print(f"    chain order={sc.get('order')} src={sc.get('order_source')}"
              f" reason={str(sc.get('first_reason'))[:80]!r}")

print("\n═══ 2. bg별 실제 첨부(attached_ref_labels) ═══")
viol = []
for bid, e in sorted(groups.items()):
    if not isinstance(e, dict) or e.get("status") != "ok":
        continue
    lin = e.get("attached_reference_lineage") or {}
    labels = lin.get("attached_ref_labels") or []
    sc = e.get("stage_chain") or {}
    tag = ""
    if sc:
        tag = (f" [chain#{sc.get('chain_index')} prev={sc.get('prev_bg_id') or '-'}"
               f"/{sc.get('prev_source') or '-'}]")
    if e.get("is_reuse"):
        tag += " [reuse]"
    print(f"  {bid}: refs={len(labels)} {labels}{tag}")
    kinds = [x.split(":", 1)[0] for x in labels]
    # 검증: 체인 plate 는 aerial+bg(prev)만 ≤2
    if sc:
        if len(labels) > 2 or not set(kinds) <= {"aerial", "bg"}:
            viol.append((bid, "chain plate ref 위반", labels))
    # 검증: aerial 과 building_fp 동시 금지
    if "aerial" in kinds and "building_fp" in kinds:
        viol.append((bid, "aerial∧building_fp 동시", labels))

print("\n═══ 3. 실내 plate 외부 ref 검사 ═══")
mp = json.loads((CP / "background_master_plan" / "manifest.json").read_text())
cat = mp["data"].get("background_catalog") or {}
for bid, e in sorted(groups.items()):
    if not isinstance(e, dict) or e.get("status") != "ok":
        continue
    role = (cat.get(bid) or {}).get("surface_role", "interior_room")
    if role != "interior_room":
        continue
    lin = e.get("attached_reference_lineage") or {}
    labels = lin.get("attached_ref_labels") or []
    kinds = [x.split(":", 1)[0] for x in labels]
    bad = [k for k in kinds if k in ("building_anchor", "aerial")]
    mark = "  ← ★위반" if bad else ""
    if bad:
        viol.append((bid, "실내 plate 외부 ref", labels))
    print(f"  {bid}: {labels}{mark}")

print("\n═══ 4. 실내 분류 loc 의 외관 plate anchor 유지(L09B01 류) ═══")
for bid, e in sorted(groups.items()):
    if not isinstance(e, dict) or e.get("status") != "ok":
        continue
    role = (cat.get(bid) or {}).get("surface_role", "interior_room")
    if role == "interior_room":
        continue
    if e.get("stage_chain"):
        continue   # 체인 plate 는 anchor 미사용이 정상
    lin = e.get("attached_reference_lineage") or {}
    labels = lin.get("attached_ref_labels") or []
    print(f"  {bid} ({role}): {labels}")

print("\n═══ 5. DB input_image_ids 실측 ═══")
conn = psycopg2.connect(host="localhost", user="theroad",
                        password="theroad_dev_2026", dbname="theroad")
cur = conn.cursor()
cur.execute(
    """SELECT variant_type, pipeline_metadata->'input_image_ids'
       FROM image_asset
       WHERE project_id=%s AND episode_id=%s AND asset_type='chain_bg'
       ORDER BY variant_type""", (PID, EID))
uuid2vt = {}
cur2 = conn.cursor()
cur2.execute(
    """SELECT id, asset_type, variant_type FROM image_asset
       WHERE project_id=%s AND episode_id=%s
         AND asset_type IN ('chain_bg','location_aerial','floor_plan')""",
    (PID, EID))
for aid, at, vt in cur2.fetchall():
    uuid2vt[aid] = f"{at}:{vt}"
for vt, iids in cur.fetchall():
    if iids is None:
        continue
    names = [uuid2vt.get(x, x[:8]) for x in iids]
    print(f"  {vt}: {names}")
conn.close()

print("\n═══ 결과 ═══")
if viol:
    print(f"★ 위반 {len(viol)}건:")
    for v in viol:
        print("  -", v)
else:
    print("위반 0건 — W-M 계약 충족")
