from __future__ import annotations

import re
from html import unescape
from typing import Any
from urllib.parse import urlparse

from moviebot.models import NormalizedEpisode, NormalizedMovie, NormalizedServer
from moviebot.utils import (
    normalize_media_type,
    parse_episode_number,
    parse_season,
    safe_filename,
    source_display_name,
    strip_season_from_title,
)


def first_id(value: Any) -> str:
    if isinstance(value, dict):
        return str(value.get("id") or "")
    return ""


def names(items: list[dict[str, Any]] | list[str] | None) -> list[str]:
    result: list[str] = []
    for item in items or []:
        if isinstance(item, dict):
            name = item.get("name")
        else:
            name = item
        if name:
            result.append(str(name))
    return result


def valid_m3u8_url(value: Any) -> str:
    url = str(value or "").strip()
    if not url or url.lower() in {"null", "none", "false"}:
        return ""
    parsed = urlparse(url)
    if parsed.scheme not in {"http", "https"} or not parsed.netloc:
        return ""
    return url


def normalize_api_movie(source: str, slug: str, payload: dict[str, Any]) -> NormalizedMovie:
    movie = payload.get("movie", {})
    api_servers = payload.get("episodes", [])
    episode_count = sum(len(server.get("server_data", [])) for server in api_servers)
    tmdb_info = movie.get("tmdb", {})
    tmdb_type = tmdb_info.get("type", "") if isinstance(tmdb_info, dict) else ""
    media_type = normalize_media_type(movie.get("type", ""), episode_count, tmdb_type)
    season = parse_season(movie.get("name", ""))
    raw_title = movie.get("name") or slug
    title = strip_season_from_title(raw_title) if media_type == "tv" else raw_title
    year = str(movie.get("year") or "")
    tmdb_id = first_id(movie.get("tmdb"))
    base_name = safe_filename(f"{title} ({year}) [tmdb-{tmdb_id}]" if tmdb_id else f"{title} ({year})")
    source_name = source_display_name(source)

    servers: list[NormalizedServer] = []
    for server_index, server in enumerate(api_servers):
        server_name = re.sub(r"\s*#\d+", "", server.get("server_name", "")).strip() or "default"
        server_label = safe_filename(server_name, fallback="Server")
        normalized_server = NormalizedServer(name=server_name, priority=server_index, raw=server)
        for item in server.get("server_data", []):
            m3u8_url = valid_m3u8_url(item.get("link_m3u8"))
            if not m3u8_url:
                continue
            ep_num = 1 if media_type == "movie" else parse_episode_number(item.get("slug", ""), item.get("name", ""), item.get("filename", ""))
            if media_type == "movie":
                filename = safe_filename(f"{base_name} - {source_name} - {server_label}")
            else:
                filename = safe_filename(f"{source_name} - {server_label}")
            normalized_server.episodes.append(
                NormalizedEpisode(
                    source_episode_id=str(item.get("slug") or item.get("name") or item.get("filename") or ep_num),
                    title=str(item.get("name") or item.get("filename") or filename),
                    filename=filename,
                    season=season,
                    episode=ep_num,
                    m3u8_url=m3u8_url,
                    raw=item,
                )
            )
        servers.append(normalized_server)

    return NormalizedMovie(
        source=source,
        source_slug=slug,
        title=str(title),
        original_title=str(movie.get("origin_name") or ""),
        year=year,
        media_type=media_type,
        tmdb_id=tmdb_id,
        imdb_id=first_id(movie.get("imdb")),
        poster_url=str(movie.get("poster_url") or ""),
        backdrop_url=str(movie.get("thumb_url") or ""),
        runtime=str(movie.get("time") or ""),
        content=unescape(str(movie.get("content") or "")),
        genres=names(movie.get("category")),
        countries=names(movie.get("country")),
        actors=names(movie.get("actor")),
        directors=names(movie.get("director")),
        raw=payload,
        servers=servers,
    )
