"""이미지 생성 파이프라인 캔버스 그래프 스키마.

설계 SOT: docs/w21b-pipeline-canvas-ui-20260629/design.html (§9 Codex 반영).
모든 노드 = 이미지(image_asset 또는 checkpoint virtual). 엣지 = 생성 입력 관계.
read-only 시각화 전용 — 메인 파이프라인 무접촉.
"""

from typing import Dict, List, Optional

from pydantic import BaseModel


class PipelineNode(BaseModel):
    """파이프라인 그래프의 노드(=이미지) 하나."""

    id: str
    # "image_asset" = DB image_asset row, "checkpoint_virtual" = ImageAsset 에 없는
    # 가이드/스케치류(checkpoint 산출물). DB sync miss 를 숨기지 않기 위해 명시.
    node_origin: str = "image_asset"
    asset_type: str  # reference|floor_plan|chain_bg|background_chain_node|composite|scene|guide
    guide_kind: Optional[str] = None  # virtual 노드일 때 (composition_guide|pose_guide|anchor_sketch ...)

    entity_id: Optional[str] = None
    entity_short_id: Optional[str] = None
    entity_name: Optional[str] = None
    entity_type: Optional[str] = None  # character|location|prop|outlook

    still_id: Optional[str] = None
    scene_index: Optional[int] = None
    shot_index: Optional[int] = None
    episode_id: Optional[str] = None
    variant_label: Optional[str] = None

    thumb_url: Optional[str] = None  # image_asset 노드만 (?thumb=1). virtual 은 full_url 직접.
    full_url: str
    prompt: Optional[str] = None  # image_asset.prompt_used (표시용)
    # llm_call_log.user_prompt — Task4 call-level overlay(still_id 구조키 조인, 있을 때만).
    prompt_authoritative: Optional[str] = None
    # 이 still 의 scene_image_gen 호출에 attach된 ref 라벨 개수(내용 파싱 없이 len 만).
    actual_ref_count: Optional[int] = None

    status: Optional[str] = None
    created_at: Optional[str] = None

    # ── persist-all Wave3: 중간물/lineage 시각화 ──────────────────────────────
    # pipeline_role: reference_face|scene_still|background_render|angle_camera_diagram|
    #   scene_regeneration_candidate ... (캔버스 색/필터·stripe/badge). None=미상.
    pipeline_role: Optional[str] = None
    # disposition: accepted|rejected|diagnostic|cache_hit_source (node badge+필터).
    disposition: Optional[str] = None
    # 중간물 여부 — 캔버스 기본 표시하되 토글로 숨김(대형 그래프). 최종물=False.
    is_intermediate: bool = False


class PipelineEdge(BaseModel):
    """생성 입력 엣지: source 이미지가 target 이미지 생성에 입력으로 쓰임."""

    # React Flow 안정 id(결정론). build_pipeline_graph 가 ``kind:source:target``
    # (+중복 시 ``#n`` suffix)로 부여 — index 기반 id는 필터/재레이아웃 때 흔들림(Codex).
    id: str = ""
    source: str
    target: str
    kind: str  # i2i | reference | background | fp | prev_scene | generated_input
    # 엣지 생성 근거(구조 키). design §9.2 + Codex 보강(2026-06-29):
    #   direct_fk            i2i 이미지 self-FK (source_image_id/parent_image_id)
    #   still_fk_resolved    prev_scene — still.dependent_scene_id(이미지 아닌 still FK)를 대표 이미지로 해석
    #   checkpoint_structural fp→bg 등 체크포인트 구조 키
    #   lineage_reference    reference_image_ids(의도된 인물/소품 lineage)
    #   planned_only         bg_map 상 계획됨 — 실제 attach 미확정
    confidence: str
    # call_log 대조 결과(design §9.2 + Codex). 기본은 구조 추론(=라벨 의미파싱 없음):
    #   verified_direct            진짜 이미지 UUID FK (i2i)
    #   structural_inferred        구조 키로만 추론 (reference/fp/prev_scene)
    #   unverified                 bg→scene 계획만, call_log 매칭 없음
    #   call_log_no_refs           해당 still 호출에 ref 0개 → planned bg 미attach 확정
    #   refs_present_unresolved    호출에 ref 있었으나 어떤 planned edge인지 UUID 매칭 불가
    verification_status: str = "structural_inferred"
    bg_id: Optional[str] = None
    # call-level overlay 투명성(Codex): bg edge의 해당 still 호출 ref 개수(0 → UI 점선/회색).
    call_ref_count: Optional[int] = None
    # prev_scene 전용: 해석에 쓰인 의존 still UUID + source 이미지 선택 규칙.
    dependent_still_id: Optional[str] = None
    source_selection: Optional[str] = None  # "is_primary_or_latest"


class EpisodeRef(BaseModel):
    id: str
    label: Optional[str] = None


class PipelineGraphResponse(BaseModel):
    episode_id: Optional[str] = None
    nodes: List[PipelineNode] = []
    edges: List[PipelineEdge] = []
    episodes: List[EpisodeRef] = []
    # settings.background_chain_enabled — False면 배경 산출물은 존재해도 현재 scene
    # consumer가 사용 안 함(그래프엔 표시하되 UI가 오해 없이 배지 표기, Codex 보강).
    background_consumer_enabled: Optional[bool] = None
    # Wave3 진단(silent drop 금지, Codex): graph builder 가 방어적으로 skip 한 것의 집계.
    #   dangling_input_refs — input_image_ids 중 노드에 없는 끝점(엣지 미생성) 개수.
    diagnostics: Optional[Dict[str, int]] = None
