"""Pydantic models for NFO metadata based on Kodi/XBMC standard.

This module provides data models for tvshow.nfo files that are compatible
with media center applications like Kodi, Plex, and Jellyfin.

Example:
    >>> nfo = TVShowNFO(
    ...     title="Attack on Titan",
    ...     year=2013,
    ...     tmdbid=1429
    ... )
    >>> nfo.premiered = "2013-04-07"
"""

from datetime import datetime
from typing import List, Optional

from pydantic import BaseModel, Field, HttpUrl, field_validator


class RatingInfo(BaseModel):
    """Rating information from various sources.
    
    Attributes:
        name: Source of the rating (e.g., 'themoviedb', 'imdb')
        value: Rating value (typically 0-10)
        votes: Number of votes
        max_rating: Maximum possible rating (default: 10)
        default: Whether this is the default rating to display
    """
    
    name: str = Field(..., description="Rating source name")
    value: float = Field(..., ge=0, description="Rating value")
    votes: Optional[int] = Field(None, ge=0, description="Number of votes")
    max_rating: int = Field(10, ge=1, description="Maximum rating value")
    default: bool = Field(False, description="Is this the default rating")
    
    @field_validator('value')
    @classmethod
    def validate_value(cls, v: float, info) -> float:
        """Ensure rating value doesn't exceed max_rating."""
        # Note: max_rating is not available yet during validation,
        # so we use a reasonable default check
        if v > 10:
            raise ValueError("Rating value cannot exceed 10")
        return v


class ActorInfo(BaseModel):
    """Actor/cast member information.
    
    Attributes:
        name: Actor's name
        role: Character name/role
        thumb: URL to actor's photo
        profile: URL to actor's profile page
        tmdbid: TMDB ID for the actor
    """
    
    name: str = Field(..., description="Actor's name")
    role: Optional[str] = Field(None, description="Character role")
    thumb: Optional[HttpUrl] = Field(None, description="Actor photo URL")
    profile: Optional[HttpUrl] = Field(None, description="Actor profile URL")
    tmdbid: Optional[int] = Field(None, description="TMDB actor ID")


class ImageInfo(BaseModel):
    """Image information for posters, fanart, and logos.
    
    Attributes:
        url: URL to the image
        aspect: Image aspect/type (e.g., 'poster', 'clearlogo', 'logo')
        season: Season number for season-specific images
        type: Image type (e.g., 'season')
    """
    
    url: HttpUrl = Field(..., description="Image URL")
    aspect: Optional[str] = Field(
        None,
        description="Image aspect (poster, clearlogo, logo)"
    )
    season: Optional[int] = Field(None, ge=-1, description="Season number")
    type: Optional[str] = Field(None, description="Image type")


class NamedSeason(BaseModel):
    """Named season information.
    
    Attributes:
        number: Season number
        name: Season name/title
    """
    
    number: int = Field(..., ge=0, description="Season number")
    name: str = Field(..., description="Season name")


class UniqueID(BaseModel):
    """Unique identifier from various sources.
    
    Attributes:
        type: ID source type (tmdb, imdb, tvdb)
        value: The ID value
        default: Whether this is the default ID
    """
    
    type: str = Field(..., description="ID type (tmdb, imdb, tvdb)")
    value: str = Field(..., description="ID value")
    default: bool = Field(False, description="Is default ID")


class TVShowNFO(BaseModel):
    """Main tvshow.nfo structure following Kodi/XBMC standard.
    
    This model represents the complete metadata for a TV show that can be
    serialized to XML for use with media center applications.
    
    Attributes:
        title: Main title of the show
        originaltitle: Original title (e.g., in original language)
        showtitle: Show title (often same as title)
        sorttitle: Title used for sorting
        year: Release year
        plot: Full plot description
        outline: Short plot summary
        tagline: Show tagline/slogan
        runtime: Episode runtime in minutes
        mpaa: Content rating (e.g., TV-14, TV-MA)
        certification: Additional certification info
        premiered: Premiere date (YYYY-MM-DD format)
        status: Show status (e.g., 'Continuing', 'Ended')
        studio: List of production studios
        genre: List of genres
        country: List of countries
        tag: List of tags/keywords
        ratings: List of ratings from various sources
        userrating: User's personal rating
        watched: Whether the show has been watched
        playcount: Number of times watched
        tmdbid: TMDB ID
        imdbid: IMDB ID
        tvdbid: TVDB ID
        uniqueid: List of unique IDs
        thumb: List of thumbnail/poster images
        fanart: List of fanart/backdrop images
        actors: List of cast members
        namedseason: List of named seasons
        trailer: Trailer URL
        dateadded: Date when added to library
    """
    
    # Required fields
    title: str = Field(..., description="Show title", min_length=1)
    
    # Basic information (optional)
    originaltitle: Optional[str] = Field(None, description="Original title")
    showtitle: Optional[str] = Field(None, description="Show title")
    sorttitle: Optional[str] = Field(None, description="Sort title")
    year: Optional[int] = Field(
        None,
        ge=1900,
        le=2100,
        description="Release year"
    )
    
    # Plot and description
    plot: Optional[str] = Field(None, description="Full plot description")
    outline: Optional[str] = Field(None, description="Short plot summary")
    tagline: Optional[str] = Field(None, description="Show tagline")
    
    # Technical details
    runtime: Optional[int] = Field(
        None,
        ge=0,
        description="Episode runtime in minutes"
    )
    mpaa: Optional[str] = Field(None, description="Content rating")
    fsk: Optional[str] = Field(
        None,
        description="German FSK rating (e.g., 'FSK 12', 'FSK 16')"
    )
    certification: Optional[str] = Field(
        None,
        description="Certification info"
    )
    
    # Status and dates
    premiered: Optional[str] = Field(
        None,
        description="Premiere date (YYYY-MM-DD)"
    )
    status: Optional[str] = Field(None, description="Show status")
    dateadded: Optional[str] = Field(
        None,
        description="Date added to library"
    )
    
    # Multi-value fields
    studio: List[str] = Field(
        default_factory=list,
        description="Production studios"
    )
    genre: List[str] = Field(
        default_factory=list,
        description="Genres"
    )
    country: List[str] = Field(
        default_factory=list,
        description="Countries"
    )
    tag: List[str] = Field(
        default_factory=list,
        description="Tags/keywords"
    )
    
    # IDs
    tmdbid: Optional[int] = Field(None, description="TMDB ID")
    imdbid: Optional[str] = Field(None, description="IMDB ID")
    tvdbid: Optional[int] = Field(None, description="TVDB ID")
    uniqueid: List[UniqueID] = Field(
        default_factory=list,
        description="Unique IDs"
    )
    
    # Ratings and viewing info
    ratings: List[RatingInfo] = Field(
        default_factory=list,
        description="Ratings"
    )
    userrating: Optional[float] = Field(
        None,
        ge=0,
        le=10,
        description="User rating"
    )
    watched: bool = Field(False, description="Watched status")
    playcount: Optional[int] = Field(
        None,
        ge=0,
        description="Play count"
    )
    
    # Media
    thumb: List[ImageInfo] = Field(
        default_factory=list,
        description="Thumbnail images"
    )
    fanart: List[ImageInfo] = Field(
        default_factory=list,
        description="Fanart images"
    )
    
    # Cast and crew
    actors: List[ActorInfo] = Field(
        default_factory=list,
        description="Cast members"
    )
    
    # Seasons
    namedseason: List[NamedSeason] = Field(
        default_factory=list,
        description="Named seasons"
    )
    
    # Additional
    trailer: Optional[HttpUrl] = Field(None, description="Trailer URL")
    
    @field_validator('premiered')
    @classmethod
    def validate_premiered_date(cls, v: Optional[str]) -> Optional[str]:
        """Validate premiered date format (YYYY-MM-DD)."""
        if v is None:
            return v
        
        # Check format strictly: YYYY-MM-DD
        if len(v) != 10 or v[4] != '-' or v[7] != '-':
            raise ValueError(
                "Premiered date must be in YYYY-MM-DD format"
            )
        
        try:
            datetime.strptime(v, '%Y-%m-%d')
        except ValueError as exc:
            raise ValueError(
                "Premiered date must be in YYYY-MM-DD format"
            ) from exc
        
        return v
    
    @field_validator('dateadded')
    @classmethod
    def validate_dateadded(cls, v: Optional[str]) -> Optional[str]:
        """Validate dateadded format (YYYY-MM-DD HH:MM:SS)."""
        if v is None:
            return v
        
        # Check format strictly: YYYY-MM-DD HH:MM:SS
        if len(v) != 19 or v[4] != '-' or v[7] != '-' or v[10] != ' ' or v[13] != ':' or v[16] != ':':
            raise ValueError(
                "Dateadded must be in YYYY-MM-DD HH:MM:SS format"
            )
        
        try:
            datetime.strptime(v, '%Y-%m-%d %H:%M:%S')
        except ValueError as exc:
            raise ValueError(
                "Dateadded must be in YYYY-MM-DD HH:MM:SS format"
            ) from exc
        
        return v
    
    @field_validator('imdbid')
    @classmethod
    def validate_imdbid(cls, v: Optional[str]) -> Optional[str]:
        """Validate IMDB ID format (should start with 'tt')."""
        if v is None:
            return v
        
        if not v.startswith('tt'):
            raise ValueError("IMDB ID must start with 'tt'")
        
        if not v[2:].isdigit():
            raise ValueError("IMDB ID must be 'tt' followed by digits")
        
        return v
    
    def model_post_init(self, __context) -> None:
        """Set default values after initialization."""
        # Set showtitle to title if not provided
        if self.showtitle is None:
            self.showtitle = self.title
        
        # Set originaltitle to title if not provided
        if self.originaltitle is None:
            self.originaltitle = self.title
