"""
Project-related schemas.
"""
from typing import List, Optional, Dict, Any
from datetime import datetime
from pydantic import BaseModel, Field, field_validator, ConfigDict

from .common import StoryboardStatus
from .asset import Asset
from .generation import GenerationRecord


class Episode(BaseModel):
    id: str
    title: str
    order: int
    desc: Optional[str] = None
    content: Optional[str] = None
    status: StoryboardStatus = 'draft'

    model_config = ConfigDict(populate_by_name=True)


class Storyboard(BaseModel):
    id: str
    episode_id: str = Field(..., alias="episodeId")
    order: int
    shot: str
    desc: str
    duration: str
    type: str
    scene_id: Optional[str] = Field(None, alias="sceneId")
    character_ids: List[str] = Field(default_factory=list, alias="characterIds")
    prop_ids: List[str] = Field(default_factory=list, alias="propIds")

    # Production details
    voiceover: Optional[str] = None
    audio_desc: Optional[str] = Field(None, alias="audioDesc")
    audio_url: Optional[str] = Field(None, alias="audioUrl")
    camera_movement: Optional[str] = Field(None, alias="cameraMovement")
    transition: Optional[str] = None

    # Cinematic Control
    camera_angle: Optional[str] = Field(None, alias="cameraAngle")
    lens: Optional[str] = None
    focus: Optional[str] = None
    lighting: Optional[str] = None
    color_style: Optional[str] = Field(None, alias="colorStyle")

    # Context
    location: Optional[str] = None
    time: Optional[str] = None

    # Source text and prompts
    original_text: Optional[str] = Field(None, alias="originalText")
    merge_image_prompt: Optional[str] = Field(None, alias="mergeImagePrompt")
    video_prompt: Optional[str] = Field(None, alias="videoPrompt")

    image_urls: Optional[List[str]] = Field(None, alias="imageUrls")
    video_urls: Optional[List[str]] = Field(None, alias="videoUrls")
    generations: Optional[List[GenerationRecord]] = []

    model_config = ConfigDict(populate_by_name=True)


class InitializeProjectRequest(BaseModel):
    name: str
    novel_text: str = Field(..., alias="novelText")
    style: str = "anime"
    description: Optional[str] = ""
    model: Optional[str] = None
    provider: Optional[str] = None

    model_config = ConfigDict(populate_by_name=True)


class CreateProjectRequest(BaseModel):
    name: str = Field(..., description="Project name")
    description: Optional[str] = Field(None, description="Project description")
    type: str = Field("canvas", description="Project type")
    chapters: Optional[List[Dict[str, Any]]] = Field(None, description="Chapters")
    assets: Optional[List[Dict[str, Any]]] = Field(None, description="Assets")

    @field_validator('name')
    @classmethod
    def validate_name(cls, v: str) -> str:
        """Validate project name"""
        if not v or not v.strip():
            from src.utils.errors import InvalidParameterException
            raise InvalidParameterException("name", "Project name cannot be empty")

        if len(v.strip()) > 200:
            from src.utils.errors import InvalidParameterException
            raise InvalidParameterException("name", "Project name cannot exceed 200 characters")

        return v.strip()


class UpdateProjectRequest(BaseModel):
    name: Optional[str] = None
    description: Optional[str] = None
    resolution: Optional[str] = None
    ratio: Optional[str] = None
    style_id: Optional[str] = Field(None, alias="styleId")
    style_params: Optional[Dict[str, Any]] = Field(None, alias="styleParams")
    chapters: Optional[List[Dict[str, Any]]] = None
    assets: Optional[List[Dict[str, Any]]] = None
    general_canvases: Optional[List[Dict[str, Any]]] = Field(None, alias="generalCanvases")

    model_config = ConfigDict(populate_by_name=True)


class InitializationProgress(BaseModel):
    """Progress information for project initialization"""
    current_step: str = Field(default="", description="Current step name")
    percentage: int = Field(default=0, ge=0, le=100, description="Overall progress percentage")
    message: str = Field(default="", description="User-friendly progress message")
    details: Optional[Dict[str, Any]] = Field(default=None, description="Additional details like counts")

    model_config = ConfigDict(populate_by_name=True)


class ProjectData(BaseModel):
    id: str
    name: str
    description: Optional[str]
    type: str
    created_at: datetime
    updated_at: datetime
    status: str
    resolution: Optional[str] = None
    ratio: Optional[str] = None
    style_id: Optional[str] = Field(None, alias="styleId")
    style_params: Optional[Dict[str, Any]] = Field(None, alias="styleParams")
    assets: List[Asset] = []
    episodes: List[Episode] = []
    storyboards: List[Storyboard] = []
    chapters: Optional[List[Dict[str, Any]]] = None
    general_canvases: List[Dict[str, Any]] = []

    # Initialization progress tracking
    progress: Optional[InitializationProgress] = None
    error: Optional[Dict[str, Any]] = None

    # User association
    user_id: Optional[str] = Field(None, alias="userId", description="Project owner ID")

    model_config = ConfigDict(populate_by_name=True)


# Episode requests
class CreateEpisodeRequest(BaseModel):
    title: str
    order: int
    desc: Optional[str] = None
    status: StoryboardStatus = 'draft'


class UpdateEpisodeRequest(BaseModel):
    title: Optional[str] = None
    order: Optional[int] = None
    desc: Optional[str] = None
    content: Optional[str] = None
    status: Optional[StoryboardStatus] = None


# Storyboard requests
class CreateStoryboardRequest(BaseModel):
    episode_id: str = Field(..., alias="episodeId")
    order: int
    shot: str
    desc: str
    duration: str
    type: str
    scene_id: Optional[str] = Field(None, alias="sceneId")
    character_ids: List[str] = Field(default_factory=list, alias="characterIds")
    prop_ids: List[str] = Field(default_factory=list, alias="propIds")

    # Production details
    voiceover: Optional[str] = None
    audio_desc: Optional[str] = Field(None, alias="audioDesc")
    audio_url: Optional[str] = Field(None, alias="audioUrl")
    camera_movement: Optional[str] = Field(None, alias="cameraMovement")
    transition: Optional[str] = None

    # Cinematic Control
    camera_angle: Optional[str] = Field(None, alias="cameraAngle")
    lens: Optional[str] = None
    focus: Optional[str] = None
    lighting: Optional[str] = None
    color_style: Optional[str] = Field(None, alias="colorStyle")

    # Context
    location: Optional[str] = None
    time: Optional[str] = None

    # Prompts
    original_text: Optional[str] = Field(None, alias="originalText")
    merge_image_prompt: Optional[str] = Field(None, alias="mergeImagePrompt")
    video_prompt: Optional[str] = Field(None, alias="videoPrompt")

    image_urls: Optional[List[str]] = Field(None, alias="imageUrls")
    video_urls: Optional[List[str]] = Field(None, alias="videoUrls")

    model_config = ConfigDict(populate_by_name=True)


class UpdateStoryboardRequest(BaseModel):
    episode_id: Optional[str] = Field(None, alias="episodeId")
    order: Optional[int] = None
    shot: Optional[str] = None
    desc: Optional[str] = None
    duration: Optional[str] = None
    type: Optional[str] = None
    scene_id: Optional[str] = Field(None, alias="sceneId")
    character_ids: Optional[List[str]] = Field(None, alias="characterIds")
    prop_ids: Optional[List[str]] = Field(None, alias="propIds")

    # Production details
    voiceover: Optional[str] = None
    audio_desc: Optional[str] = Field(None, alias="audioDesc")
    audio_url: Optional[str] = Field(None, alias="audioUrl")
    camera_movement: Optional[str] = Field(None, alias="cameraMovement")
    transition: Optional[str] = None

    # Cinematic Control
    camera_angle: Optional[str] = Field(None, alias="cameraAngle")
    lens: Optional[str] = None
    focus: Optional[str] = None
    lighting: Optional[str] = None
    color_style: Optional[str] = Field(None, alias="colorStyle")

    # Context
    location: Optional[str] = None
    time: Optional[str] = None

    # Prompts
    original_text: Optional[str] = Field(None, alias="originalText")
    merge_image_prompt: Optional[str] = Field(None, alias="mergeImagePrompt")
    video_prompt: Optional[str] = Field(None, alias="videoPrompt")

    image_urls: Optional[List[str]] = Field(None, alias="imageUrls")
    video_urls: Optional[List[str]] = Field(None, alias="videoUrls")
    generations: Optional[List[GenerationRecord]] = None

    model_config = ConfigDict(populate_by_name=True)
