"""이미지 API 스키마."""

from typing import Optional

from pydantic import BaseModel, Field, field_validator

from app.core.file_paths import to_relative_image_path


class ImageResponse(BaseModel):
    id: str
    asset_type: str
    # 2a (2026-07-01): image role taxonomy — Entities/캔버스가 fp/항공/배경/
    # 실내마네킹/실외마네킹 을 asset_type 만으로 못 나누므로 pipeline_role 노출.
    pipeline_role: Optional[str] = None
    # #8 (2026-07-02): 중간과정/거부본을 최종 참조와 동레벨로 섞지 않기 위한
    # persist-all 컬럼 노출 (disposition: accepted|rejected|diagnostic|
    # cache_hit_source, NULL=최종물).
    is_intermediate: bool = False
    disposition: Optional[str] = None
    entity_id: Optional[str] = None
    still_id: Optional[str] = None
    episode_id: Optional[str] = None
    file_path: str
    prompt_used: Optional[str] = None
    generation_model: Optional[str] = None
    width: Optional[int] = None
    height: Optional[int] = None
    status: str
    review_notes: str
    validation_score: Optional[int] = None
    validation_result: Optional[str] = None
    sanitization_strategy: Optional[str] = None
    original_prompt: Optional[str] = None
    sanitization_note: Optional[str] = None
    variant_type: Optional[str] = None        # original | variant_a | variant_b
    angle_applied: Optional[str] = None       # JSON of angle params applied
    color_applied: Optional[str] = None       # color prompt applied
    source_image_id: Optional[str] = None     # parent image ID for i2i chain
    is_primary: bool = False
    prompt_type: Optional[str] = None         # cinematic | closeup | original
    code_version: Optional[str] = None
    prompt_file_version: Optional[str] = None
    reference_image_ids: str = Field(
        default="[]",
        description=(
            "(lineage) JSON array of visible_entities character/prop UUID list. "
            "NOT actual LLM-attached refs — for actual refs see actual_attached_refs."
        ),
    )
    actual_attached_refs: Optional[list[str]] = Field(
        default=None,
        description=(
            "Actual ref labels attached to the LLM call "
            "(joined from llm_call_log.reference_image_ids — most recent entry "
            "matching still_id). None when log entry not found, retention exceeded, "
            "or caller did not pass db/actual_refs_cache."
        ),
    )
    created_at: str

    # Enriched fields (parsed from angle_applied / still context)
    angle_horizontal: Optional[int] = None
    angle_vertical: Optional[int] = None
    angle_zoom: Optional[float] = None
    color_prompt: Optional[str] = None
    is_recommended: Optional[bool] = None
    selected_for_pdf: Optional[bool] = None
    recommendation_reason: Optional[str] = None

    model_config = {"from_attributes": True}

    @field_validator("file_path", mode="before")
    @classmethod
    def _normalize_file_path(cls, v):
        """ORM의 ImagePathType은 read 시 절대 경로 string 을 반환한다.
        API 응답에는 절대 호스트 경로가 누출되지 않도록 상대로 환원한다 (Codex B2)."""
        if not v:
            return v
        return to_relative_image_path(v)


class ValidationResponse(BaseModel):
    image_id: str
    score: Optional[int] = None
    passed: Optional[bool] = None
    issues: list[str] = []
    description: str = ""


class ReviewUpdate(BaseModel):
    status: str  # 'approved' | 'needs_fix'
    notes: str = ""
