from enum import Enum
from typing import Optional, List, Tuple, Union

from pydantic import BaseModel, Field, ConfigDict

from .imdbapi import ImdbApiTitle, ImdbApiEpisode, ImdbApiCredit, ImdbapiImage
from .imdbtypes import ImdbTitle, ImdbName, ImdbImage, ImdbVideo, AkasNode, TitleEdge


class ErrorType(Enum):
    PERSISTED_QUERY_NOT_FOUND = 'PERSISTED_QUERY_NOT_FOUND'


class StaffPickEntry(BaseModel):
    name: str
    ttconst: str = Field(..., alias='id')
    rmconst: str
    detail: Optional[str] = ""
    description: Optional[str] = ""
    relatedconst: List[str] = Field(default_factory=list, alias='relatedConst')
    viconst: Optional[str] = None


class VerticalList(BaseModel):
    titles: List[ImdbTitle] = Field(default_factory=list)
    names: List[ImdbName] = Field(default_factory=list)
    videos: List[ImdbVideo] = Field(default_factory=list)
    images: List[ImdbImage] = Field(default_factory=list)


class StaffPickApiResponse(BaseModel):
    updated_at: Optional[str]
    entries: List[StaffPickEntry] = Field(default_factory=list)
    imdb_items: VerticalList


class ImdbMediaInfo(ImdbApiTitle):
    akas: List[AkasNode] = Field(default_factory=list)
    episodes: List[ImdbApiEpisode] = Field(default_factory=list)
    credits: List[ImdbApiCredit] = Field(default_factory=list)
    images: List[ImdbapiImage] = Field(default_factory=list)

    @classmethod
    def from_title(
        cls,
        title: ImdbApiTitle,
        akas: Optional[List[AkasNode]] = None,
        episodes: Optional[List[ImdbApiEpisode]] = None,
        api_credits: Optional[List[ImdbApiCredit]] = None,
        images: Optional[List[ImdbapiImage]] = None
    ) -> "ImdbMediaInfo":
        fields = {
            **title.model_dump(exclude_none=True, by_alias=True),
        }
        if akas is not None:
            fields['akas'] = akas
        if episodes is not None:
            fields['episodes'] = episodes
        if api_credits is not None:
            fields['credits'] = api_credits
        if images is not None:
            fields['images'] = images
        return cls(**fields)

    def backdrop_path(self) -> str | None:
        if self.images:
            for image in self.images:
                if image.url and image.type == 'still_frame':
                    # replace('@._V1', '@._V1_QL75_UX327_')
                    return image.url
        return None

class ImdbApiHash(BaseModel):
    advanced_title_search: str = Field(alias="AdvancedTitleSearch")


class PageInfo(BaseModel):
    has_previous_page: Optional[bool] = Field(None, alias="hasPreviousPage")
    has_next_page: Optional[bool] = Field(None, alias="hasNextPage")
    start_cursor: Optional[str] = Field(None, alias="startCursor")
    end_cursor: Optional[str] = Field(None, alias="endCursor")


class FilterInfo(BaseModel):
    filter_id: Optional[str] = Field(default=None, alias='filterId')
    text: Optional[str] = Field(default=None, alias='text')
    total: Optional[int] = Field(default=None, alias='total')


class SearchState(BaseModel):
    total: int = 0
    page_info: PageInfo = Field(default_factory=PageInfo, alias="pageInfo")
    genres: List[FilterInfo] = Field(default_factory=list)
    keywords: List[FilterInfo] = Field(default_factory=list)
    title_types: List[FilterInfo] = Field(default_factory=list, alias='titleTypes')


class AdvancedTitleSearch(SearchState):
    edges: List[TitleEdge] = Field(default_factory=list)


class AdvancedTitleSearchResponse(BaseModel):
    advanced_title_search: AdvancedTitleSearch = Field(default_factory=AdvancedTitleSearch, alias="advancedTitleSearch")


class SearchParams(BaseModel):
    title_types: Optional[Tuple[str, ...]] = None
    genres: Optional[Tuple[str, ...]] = None
    sort_by: str = 'POPULARITY'
    sort_order: str = 'ASC'
    rating_min: Optional[float] = None
    rating_max: Optional[float] = None
    countries: Optional[Tuple[str, ...]] = None
    languages: Optional[Tuple[str, ...]] = None
    release_date_end: Optional[str] = None
    release_date_start: Optional[str] = None
    award_constraint: Optional[Tuple[str, ...]] = None
    ranked: Optional[Tuple[str, ...]] = None
    interests: Optional[Tuple[str, ...]] = None
    company: Optional[str] = None

    model_config = ConfigDict(
        frozen=True
    )


class ErrorExtension(BaseModel):
    code: Union[ErrorType, str]
    error_type: str = Field('CLIENT', alias='errorType')
    is_retryable: bool = Field(False, alias='isRetryable')


class ErrorValue(BaseModel):
    message: Optional[str] = Field(default=None, alias='message')
    extensions: Optional[ErrorExtension]


class ErrorResponse(BaseModel):
    errors: Optional[List[ErrorValue]] = Field(default_factory=list)
