"""프로젝트 범위 모델 — PostgreSQL 단일 데이터베이스에 저장."""

from sqlalchemy import Column, Text, Integer, ForeignKey, UniqueConstraint
from sqlalchemy.orm import deferred
from app.core.database import Base


class Episode(Base):
    __tablename__ = "episode"

    id = Column(Text, primary_key=True)
    project_id = Column(Text, ForeignKey("project_registry.id"), nullable=False)
    episode_number = Column(Integer, nullable=False)
    title = Column(Text, nullable=False)
    source_filename = Column(Text, nullable=False)
    source_path = Column(Text, nullable=False)
    fulltext = deferred(Column(Text))
    language = Column(Text, default="ko")
    page_count = Column(Integer)
    status = Column(Text, default="uploaded")  # uploaded|analyzing|analyzed|error
    analysis_error = Column(Text)
    summary = Column(Text)               # 에피소드 상세 요약 (분석 시 생성)
    created_at = Column(Text, nullable=False)
    updated_at = Column(Text, nullable=False)


class EntityCanon(Base):
    __tablename__ = "entity_canon"

    id = Column(Text, primary_key=True)
    project_id = Column(Text, ForeignKey("project_registry.id"), nullable=False)
    entity_type = Column(Text, nullable=False)  # character|location|prop
    name = Column(Text, nullable=False)
    description = Column(Text)
    stable_traits = Column(Text, default="{}")
    t2i_prompt = Column(Text)  # 시각적 보통명사 기반 T2I 프롬프트
    status = Column(Text, default="active")
    created_at = Column(Text, nullable=False)
    updated_at = Column(Text, nullable=False)


class CharacterOutlook(Base):
    __tablename__ = "character_outlook"

    id = Column(Text, primary_key=True)
    character_id = Column(Text, ForeignKey("entity_canon.id"), nullable=False)
    outlook_id = Column(Text, ForeignKey("entity_canon.id"), nullable=False)
    project_id = Column(Text, ForeignKey("project_registry.id"), nullable=False)
    created_at = Column(Text, nullable=False)


class EntityAlias(Base):
    __tablename__ = "entity_alias"

    id = Column(Text, primary_key=True)
    canon_id = Column(Text, ForeignKey("entity_canon.id"), nullable=False)
    alias = Column(Text, nullable=False)

    __table_args__ = (UniqueConstraint("canon_id", "alias"),)


class RelationFact(Base):
    __tablename__ = "relation_fact"

    id = Column(Text, primary_key=True)
    project_id = Column(Text, ForeignKey("project_registry.id"), nullable=False)
    relation_family = Column(Text, nullable=False)
    relation_type = Column(Text, nullable=False)
    directionality = Column(Text, nullable=False)
    temporal_scope = Column(Text, nullable=False)
    continuity_priority = Column(Text, nullable=False)
    continuity_reason = Column(Text)
    created_at = Column(Text, nullable=False)


class RelationParticipant(Base):
    __tablename__ = "relation_participant"

    id = Column(Text, primary_key=True)
    relation_id = Column(Text, ForeignKey("relation_fact.id"), nullable=False)
    canon_id = Column(Text, ForeignKey("entity_canon.id"), nullable=False)
    participant_role = Column(Text, nullable=False)
    participant_order = Column(Integer, default=1)


class SceneStill(Base):
    __tablename__ = "scene_still"

    id = Column(Text, primary_key=True)
    project_id = Column(Text, ForeignKey("project_registry.id"), nullable=False)
    episode_id = Column(Text, ForeignKey("episode.id"), nullable=False)
    still_index = Column(Integer, nullable=False)
    screenplay_scene_heading = Column(Text)
    beat_title = Column(Text)
    still_frame_prompt = Column(Text)
    camera_json = Column(Text, default="{}")
    lighting_json = Column(Text, default="{}")
    visible_entities_json = Column(Text, default="[]")
    t2i_prompt_cinematic = Column(Text)    # A) wide/establishing 버전 (대표 T2I)
    t2i_prompt_closeup = Column(Text)      # B) 인물 클로즈업 버전
    t2i_variations_json = Column(Text)     # N개 T2I 변형 JSON: [{theme, theme_label, t2i_prompt}]
    t2i_composer_version = Column(Text)    # 사용된 composer 프롬프트 버전
    segment_start_char = Column(Integer)   # 시나리오 원문 세그먼트 시작 위치
    segment_end_char = Column(Integer)     # 시나리오 원문 세그먼트 끝 위치
    variation_a_type = Column(Text)        # "angle" | "color" | "angle+color" | "none"
    variation_a_angle = Column(Text)       # JSON: {"horizontal": 45, "vertical": 0, "zoom": 1.0}
    variation_a_color = Column(Text)       # color edit prompt
    variation_a_reason = Column(Text)      # LLM recommendation reason
    variation_b_type = Column(Text)
    variation_b_angle = Column(Text)
    variation_b_color = Column(Text)
    variation_b_reason = Column(Text)
    recommended_variant = Column(Text)     # "original" | "A" | "B"
    selected_variant = Column(Text)        # user override (null = use recommended)
    dependent_scene_id = Column(Text)      # 앞쪽 의존 씬 ID (같은 장소 등)
    scene_type = Column(Text, default="normal")  # normal|montage|flashback|dream|voiceover|transition
    status = Column(Text, default="pending")
    created_at = Column(Text, nullable=False)


class EntityEpisodeLink(Base):
    __tablename__ = "entity_episode_link"

    id = Column(Text, primary_key=True)
    project_id = Column(Text, ForeignKey("project_registry.id"), nullable=False)
    canon_id = Column(Text, ForeignKey("entity_canon.id"), nullable=False)
    episode_id = Column(Text, ForeignKey("episode.id"), nullable=False)
    source = Column(Text, default="extracted")

    __table_args__ = (UniqueConstraint("canon_id", "episode_id"),)


class ImageAsset(Base):
    __tablename__ = "image_asset"

    id = Column(Text, primary_key=True)
    project_id = Column(Text, ForeignKey("project_registry.id"), nullable=False)
    asset_type = Column(Text, nullable=False)  # 'reference' | 'scene'
    entity_id = Column(Text)  # for reference images
    still_id = Column(Text)   # for scene images
    episode_id = Column(Text)
    file_path = Column(Text, nullable=False)
    prompt_used = Column(Text)
    generation_model = Column(Text)
    width = Column(Integer)
    height = Column(Integer)
    status = Column(Text, default="generated")  # generated|approved|needs_fix|regenerating
    review_notes = Column(Text, default="")
    validation_score = Column(Integer)       # LVM validation score 0-100
    validation_result = Column(Text)         # JSON string of full validation result
    sanitization_strategy = Column(Text)     # null=원본, "film_previs"|"movie_poster"|"aftermath"
    original_prompt = Column(Text)           # 수정 전 원본 프롬프트 (수정된 경우에만)
    sanitization_note = Column(Text)         # GPT가 어떻게 수정했는지 설명
    variant_type = Column(Text)              # "original" | "variant_a" | "variant_b"
    angle_applied = Column(Text)             # JSON of angle params applied
    color_applied = Column(Text)             # color prompt applied
    source_image_id = Column(Text)           # parent image ID for i2i chain
    is_primary = Column(Integer, default=0)  # 1 = representative image for PDF/display
    prompt_type = Column(Text)               # "cinematic" | "closeup" | "original" | None
    code_version = Column(Text)              # from version_registry at generation time
    prompt_file_version = Column(Text)       # "t2i_composer/v1" or "prompt_sanitizer/v1" etc.
    reference_image_ids = Column(Text, default="[]")  # JSON array of referenced ImageAsset IDs
    parent_image_id = Column(Text, ForeignKey("image_asset.id"))
    theme_label = Column(Text)               # v5: 변형 주제 라벨 (예: "인물 중심", "상황 중심")
    created_at = Column(Text, nullable=False)


class ProjectSettings(Base):
    __tablename__ = "project_settings"

    id = Column(Text, primary_key=True)
    project_id = Column(Text, ForeignKey("project_registry.id"), nullable=False, unique=True)
    composer_system_prompt = Column(Text)  # Override for T2I composer system prompt
    composer_user_prompt = Column(Text)    # Override for T2I composer user prompt
    style_rules_json = Column(Text)        # 프로젝트 단위 스타일 규칙 JSON
    world_summary = Column(Text)           # 프로젝트 단위 세계관 요약
    scene_split_threshold = Column(Integer, default=600)  # 씬 분할 글자수 임계값
    llm_config_json = Column(Text, default="{}")  # 단계별 LLM 모델 설정 JSON
    updated_at = Column(Text, nullable=False)


class WorldGuide(Base):
    __tablename__ = "world_guide"

    id = Column(Text, primary_key=True)
    project_id = Column(Text, ForeignKey("project_registry.id"), nullable=False)
    episode_id = Column(Text, ForeignKey("episode.id"))
    guide_json = Column(Text, nullable=False)
    source_hash = Column(Text)  # MD5 hash of inputs (fulltext + entities + stills count)
    created_at = Column(Text, nullable=False)


class WebbookPackage(Base):
    __tablename__ = "webbook_package"

    id = Column(Text, primary_key=True)
    project_id = Column(Text, ForeignKey("project_registry.id"), nullable=False)
    episode_id = Column(Text, ForeignKey("episode.id"))
    package_json = Column(Text, nullable=False)
    prompt_version = Column(Text)
    created_at = Column(Text, nullable=False)


class OperationLog(Base):
    """모든 파이프라인 작업의 프로비저닝 기록 — Opik 호환 구조."""
    __tablename__ = "operation_log"

    id = Column(Text, primary_key=True)
    project_id = Column(Text, ForeignKey("project_registry.id"), nullable=False)
    operation_type = Column(Text, nullable=False)  # entity_extraction / scene_still_extraction / image_generation / webbook_generation / pdf_rendering / validation
    episode_id = Column(Text)
    module_name = Column(Text, nullable=False)      # from version_registry
    module_version = Column(Text, nullable=False)
    prompt_name = Column(Text)                       # e.g., "entity_extraction/v5"
    prompt_version = Column(Text)                    # e.g., "v5"
    prompt_hash = Column(Text)                       # SHA256 of actual prompt content
    input_summary = Column(Text)                     # JSON: key inputs (truncated)
    output_summary = Column(Text)                    # JSON: key outputs (truncated)
    status = Column(Text, nullable=False)            # success / error / partial
    error_message = Column(Text)
    duration_ms = Column(Integer)
    token_usage = Column(Text, default="{}")         # JSON: {input_tokens, output_tokens, cost_usd}
    metadata_json = Column(Text, default="{}")       # JSON: extra context
    created_at = Column(Text, nullable=False)


class PipelineProgress(Base):
    """파이프라인 진행률 추적 — UI에서 폴링하여 표시."""
    __tablename__ = "pipeline_progress"

    id = Column(Text, primary_key=True)
    project_id = Column(Text, ForeignKey("project_registry.id"), nullable=False)
    episode_id = Column(Text, nullable=False)
    operation = Column(Text, nullable=False)  # analysis / image_generation / webbook / pdf_render
    status = Column(Text, default="running")  # running / completed / error
    current_step = Column(Text, default="")   # e.g., "엔티티 추출 중", "참조 이미지 생성 (5/26)"
    total_steps = Column(Integer, default=0)
    completed_steps = Column(Integer, default=0)
    error_message = Column(Text)
    started_at = Column(Text, nullable=False)
    updated_at = Column(Text, nullable=False)
    completed_at = Column(Text)


class LLMCallLog(Base):
    """모든 LLM 호출의 입력/출력 기록 — 추적 및 재활용."""
    __tablename__ = "llm_call_log"

    id = Column(Text, primary_key=True)
    project_id = Column(Text)
    episode_id = Column(Text)
    operation_type = Column(Text)       # entity_extraction / scene_analysis / outlook / image_gen / ...
    step_name = Column(Text)            # turn0 / scene_10 / translate / select_best / ...
    model_name = Column(Text, nullable=False)
    system_prompt = Column(Text)
    user_prompt = Column(Text, nullable=False)
    output_text = Column(Text)
    reference_image_ids = Column(Text, default="[]")  # JSON array of ImageAsset IDs
    duration_ms = Column(Integer)
    input_tokens = Column(Integer)
    output_tokens = Column(Integer)
    status = Column(Text, nullable=False)  # success / error
    error_message = Column(Text)
    created_at = Column(Text, nullable=False)


class ScenePlan(Base):
    """씬 분할 계획 — 사용자 승인 전 미리보기용."""
    __tablename__ = "scene_plan"

    id = Column(Text, primary_key=True)
    project_id = Column(Text, ForeignKey("project_registry.id"), nullable=False)
    episode_id = Column(Text, ForeignKey("episode.id"), nullable=False)
    split_threshold = Column(Integer, default=600)
    segments_json = Column(Text, nullable=False)  # JSON array of segment dicts
    total_scenes = Column(Integer, nullable=False)
    status = Column(Text, default="pending")  # pending|approved|rejected
    created_at = Column(Text, nullable=False)


class GenerationTrace(Base):
    __tablename__ = "generation_trace"

    id = Column(Text, primary_key=True)
    project_id = Column(Text, ForeignKey("project_registry.id"), nullable=False)
    image_asset_id = Column(Text)  # nullable — may not have asset yet
    still_id = Column(Text)
    entity_id = Column(Text)
    attempt_number = Column(Integer, nullable=False, default=1)
    prompt_used = Column(Text, nullable=False)
    prompt_version = Column(Text, nullable=False, default="original")  # original/sanitized_v1/sanitized_v2/alternative
    model_name = Column(Text)
    status = Column(Text, nullable=False)  # success/moderation_blocked/error/timeout
    block_reason = Column(Text)  # SAFETY, HARM, etc.
    block_categories = Column(Text, default="[]")  # JSON array
    response_time_ms = Column(Integer)
    sanitizer_feedback = Column(Text)  # GPT's explanation of changes
    created_at = Column(Text, nullable=False)
