from __future__ import annotations

import logging
import re
import unicodedata
from pathlib import Path
from typing import Any


INVALID_FILENAME = re.compile(r'[<>:"/\\|?*\x00-\x1F]')
SEASON_PATTERN = "(?:season|phan|ph\u1ea7n|ph\u00e1\u00ba\u00a7n)"


def setup_logging(log_dir: str, level: str = "INFO") -> None:
    Path(log_dir).mkdir(parents=True, exist_ok=True)
    log_file = Path(log_dir) / "moviebot.log"
    logging.basicConfig(
        level=getattr(logging, level.upper(), logging.INFO),
        format="%(asctime)s %(levelname)s %(name)s %(message)s",
        handlers=[
            logging.FileHandler(log_file, encoding="utf-8"),
            logging.StreamHandler(),
        ],
    )


def safe_filename(value: Any, max_length: int = 120, fallback: str = "untitled") -> str:
    text = unicodedata.normalize("NFKC", str(value or "")).strip()
    text = INVALID_FILENAME.sub("", text)
    text = re.sub(r"\s+", " ", text).strip().rstrip(".")
    text = "".join(ch for ch in text if ch.isprintable())
    if not text:
        text = fallback
    if len(text) > max_length:
        text = text[:max_length].rstrip()
    return text


def library_name(media_type: str) -> str:
    return "Movies" if media_type == "movie" else "TVShows"


def movie_folder_name(title: str, year: str, tmdb_id: str) -> str:
    year_part = f" ({year})" if year else ""
    tmdb_part = f" [tmdb-{tmdb_id}]" if tmdb_id else ""
    return safe_filename(f"{title}{year_part}{tmdb_part}")


def source_folder_name(source: str) -> str:
    return safe_filename(source.lower(), fallback="source")


def source_display_name(source: str) -> str:
    names = {
        "kkphim": "Kkphim",
        "ophim": "Ophim",
    }
    return names.get((source or "").lower(), safe_filename(source, fallback="Source"))


def to_db_path(path: str | Path, root_dir: str | Path, db_mount: str) -> str:
    root = Path(root_dir).resolve()
    file_path = Path(path).resolve()
    relative = file_path.relative_to(root).as_posix()
    return f"/{db_mount.strip('/')}/{relative}"


def normalize_media_type(source_type: str, episode_count: int = 0, tmdb_type: str = "") -> str:
    tmdb_value = (tmdb_type or "").lower()
    if tmdb_value in {"movie", "single"}:
        return "movie"
    if tmdb_value in {"tv", "series", "tvshows"}:
        return "tv"

    value = (source_type or "").lower()
    if value in {"single", "movie"}:
        return "movie"
    if value in {"series", "tvshows"}:
        return "tv"
    if value == "hoathinh":
        return "tv" if episode_count > 1 else "movie"
    return "tv" if episode_count > 1 else "movie"


def episode_code(season: int, episode: int) -> str:
    return f"S{season:02}E{episode:02}"


def parse_episode_number(*values: str, default: int = 1) -> int:
    for value in values:
        text = str(value or "")
        match = re.search(r"S\d{1,2}E(\d{1,3})", text, re.IGNORECASE)
        if match:
            return int(match.group(1))
        match = re.search(r"(\d+)", text)
        if match:
            return int(match.group(1))
    return default


def parse_season(title: str, default: int = 1) -> int:
    match = re.search(rf"{SEASON_PATTERN}\s*(\d+)", title or "", re.IGNORECASE)
    return int(match.group(1)) if match else default


def strip_season_from_title(title: str) -> str:
    cleaned = re.sub(
        rf"\s*[-:|]?\s*\(?{SEASON_PATTERN}\s*\d+\)?\s*$",
        "",
        title or "",
        flags=re.IGNORECASE,
    )
    return cleaned.strip() or title
