# -*- coding: utf-8 -*-
"""
Series filter: logika pro validaci sezón a epizod proti TMDb metadatům.
"""
import re
import unicodedata
from resources.lib.utils.log_utils import get_logger
from resources.lib.utils.ui_utils import _normalize_and_slugify

log = get_logger()

ARTICLE_TOKENS = {'the', 'a', 'an'}
GENERIC_TITLE_TOKENS = {
    'after', 'again', 'black', 'dark', 'echo', 'empire', 'family', 'fire',
    'home', 'hope', 'life', 'light', 'lost', 'love', 'paradise', 'pulse',
    'rescue', 'surface', 'truth', 'you'
}
TITLE_STOP_TOKENS = {'of', 'and'}
TITLE_BREAK_TOKENS = {
    '1080p', '2160p', '720p', '480p', 'hdr', 'dv', 'webrip', 'web', 'bdrip',
    'bluray', 'amzn', 'nf', 'hmax', 'dsnp', 'apple', 'atvp', 'x264', 'x265',
    'h264', 'h265', 'hevc', 'aac', 'ddp', 'ac3', 'dts', 'proper', 'repack',
    'internal', 'extended', 'dubbed', 'dub', 'multi', 'sub', 'subs', 'cz',
    'sk', 'eng', 'en', 'czsub', 'ita', 'de', 'fr', 'es', 'ru', 'ua', 'pl',
    'truefrench', 'remux', 'uhd', 'hd', 'sd'
}

def _tokens(text: str) -> list:
    """Rozbije text na jednotlivé tokeny (slova/čísla)."""
    slug = _normalize_and_slugify(text or '')
    return re.findall(r'[a-z0-9]+', slug)

def _drop_leading_the(s: str) -> str:
    """Odstraní předložku 'the' z začátku slugified názvu."""
    return s[3:] if s.startswith('the') else s

def _title_tokens(text: str) -> list:
    """Tokeny názvu bez separátorů, zachovává články pro přesné porovnání family."""
    slug = _normalize_and_slugify(text or '')
    return re.findall(r'[a-z0-9]+', slug)

def _meaningful_title_tokens(text: str) -> list:
    """Tokeny názvu bez článků a běžných spojek pro odhad rizikovosti."""
    return [
        tok for tok in _title_tokens(text)
        if tok not in ARTICLE_TOKENS and tok not in TITLE_STOP_TOKENS
    ]

def _build_exact_title_variants(titles: list) -> list:
    """Vrátí přesné tokenové varianty názvu; článek odebírá jen pokud je součástí cílového názvu."""
    variants = []
    seen = set()
    for title in titles:
        tokens = _title_tokens(title)
        if not tokens:
            continue
        variant = tuple(tokens)
        if variant not in seen:
            variants.append(variant)
            seen.add(variant)
        if tokens[0] in ARTICLE_TOKENS and len(tokens) > 1:
            short_variant = tuple(tokens[1:])
            if short_variant not in seen:
                variants.append(short_variant)
                seen.add(short_variant)
    return variants

def _unique_titles(series_name: str = '', title: str = '', original_title: str = '', aliases=None) -> list:
    aliases = aliases or []
    titles = []
    for value in [series_name, title, original_title] + list(aliases):
        value = (value or '').strip()
        if value and value not in titles:
            titles.append(value)
    return titles

def analyze_title_risk(series_name: str = '', title: str = '', original_title: str = '', aliases=None) -> dict:
    """Heuristika pro rizikový/obecný název seriálu."""
    titles = _unique_titles(series_name, title, original_title, aliases)
    meaningful_variants = [
        tuple(_meaningful_title_tokens(value))
        for value in titles
        if _meaningful_title_tokens(value)
    ]
    score = 0
    reasons = []

    if meaningful_variants:
        shortest = min(len(tokens) for tokens in meaningful_variants)
        flattened = {token for tokens in meaningful_variants for token in tokens}
        if shortest <= 1:
            score += 2
            reasons.append('single-token-title')
        if any(any(token in GENERIC_TITLE_TOKENS for token in tokens) for tokens in meaningful_variants):
            score += 2
            reasons.append('generic-token')
        if len(flattened) <= 1:
            score += 1
            reasons.append('single-meaningful-family')
        if any(len(''.join(tokens)) <= 10 for tokens in meaningful_variants):
            score += 1
            reasons.append('short-title')
    else:
        score += 2
        reasons.append('missing-title-tokens')

    return {
        'is_risky': score >= 3,
        'score': score,
        'reasons': reasons,
        'titles': titles,
    }

def build_title_gate(series_data: dict, fallback_name: str = '') -> dict:
    """Připraví exact title family varianty pro agresivní filtraci."""
    tmdb = series_data.get('tmdb') or {}
    titles = _unique_titles(
        series_data.get('name') or fallback_name,
        tmdb.get('title') or fallback_name,
        tmdb.get('original_title') or fallback_name,
        series_data.get('aliases') or []
    )
    return {
        'titles': titles,
        'variants': _build_exact_title_variants(titles),
    }

def _extract_title_prefix_tokens(filename: str) -> list:
    """Vytáhne tokeny názvové family před S/E, rokem nebo release tagy."""
    text = (filename or '').replace('.', ' ').replace('_', ' ').replace('-', ' ')
    # Normalizace diakritiky – 'Ráj' → 'Raj', aby odpovídalo slugifikovaným variantám v title_gate
    text = unicodedata.normalize('NFKD', text).encode('ascii', 'ignore').decode('utf-8')
    tokens = re.findall(r'[A-Za-z0-9]+', text.lower())
    prefix = []
    for token in tokens:
        if re.match(r'(?i)^s\d{1,2}e\d{1,3}$', token):
            break
        if re.match(r'(?i)^\d{1,2}x\d{1,3}$', token):
            break
        if re.match(r'^(19|20)\d{2}$', token):
            break
        if token in TITLE_BREAK_TOKENS:
            break
        prefix.append(token)
        if len(prefix) >= 6:
            break
    return prefix

def strict_title_match(filename: str, title_gate: dict) -> bool:
    """Agresivní režim: prefix názvu souboru musí přesně odpovídat cílové title family."""
    prefix = tuple(_extract_title_prefix_tokens(filename))
    if not prefix:
        return False
    return prefix in set(title_gate.get('variants') or [])

def detect_title_families(streams: list) -> list:
    """Vrátí nalezené názvové family mezi kandidáty pro logování rizikového mixu."""
    families = []
    seen = set()
    for stream in streams or []:
        prefix = tuple(_extract_title_prefix_tokens((stream or {}).get('name') or ''))
        if not prefix or prefix in seen:
            continue
        seen.add(prefix)
        families.append(' '.join(prefix))
    return families

def filter_invalid_seasons(series_manager, series_data: dict, buckets: dict, filter_mode: str = 'standard') -> dict:
    """
    TMDb filtr:
      - kontrola existence sezony a epizody podle TMDb
      - kontrola ročníku (rok výroby)
      - kontrola slug / fallback token-match
    """
    filter_mode = (filter_mode or 'standard').lower()
    aggressive_mode = filter_mode == 'aggressive'
    log.info(f"[SeriesFilter] Spouštím filter_invalid_seasons() režim={filter_mode}")

    tmdb = series_data.get('tmdb') or {}
    tmdb_id = tmdb.get('id')
    tmdb_year = tmdb.get('year')
    if not tmdb_id:
        log.warning("Nemám TMDb ID – filtr přeskočen")
        return buckets

    # 1) Vytvoření rozšířené sady validních slugů
    series_name     = series_data.get('name') or ''
    original_title  = tmdb.get('original_title') or ''
    saved_slug      = tmdb.get('slug')
    title_gate      = build_title_gate(series_data, fallback_name=series_name)

    valid_slugs = set()
    if saved_slug:
        valid_slugs.add(saved_slug)
    if series_name:
        valid_slugs.add(_normalize_and_slugify(series_name))
    if original_title:
        valid_slugs.add(_normalize_and_slugify(original_title))

    # varianta bez "the"
    valid_slugs |= {_drop_leading_the(s) for s in list(valid_slugs) if len(s) > 3}

    # 2) Tokenová shoda pro fallback
    series_tokens = set()
    for src in (series_name, original_title):
        for t in _tokens(src):
            if t not in ('the',):
                series_tokens.add(t)

    # 3) Načti metadata seriálu z TMDb
    try:
        from resources.lib.tmdb import tmdb_utils as TM
    except Exception:
        TM = None

    if TM is None:
        log.warning("TMDb modul nedostupný – filtr přeskočen")
        return buckets

    show_meta = TM.get_tv_show_meta(int(tmdb_id), language='cs') or {}
    num_seasons = show_meta.get('number_of_seasons', 0)
    if not tmdb_year:
        tmdb_year = show_meta.get('year')

    if not isinstance(num_seasons, int) or num_seasons <= 0:
        log.warning("TMDb nevrátil validní počet sezón – filtr přeskočen")
        return buckets

    log.info(f"[SeriesFilter] Start: TMDb ID={tmdb_id}, seasons={num_seasons}")

    # 4) Validace jednotlivých bucketů
    valid_buckets = {}

    for (s, e), streams in buckets.items():
        try:
            if s > num_seasons:
                log.debug(f"❌ Sezóna {s} je mimo TMDb rozsah")
                continue

            season_meta = TM.get_tv_season_meta(int(tmdb_id), s, language='cs') or {}
            episodes_meta = season_meta.get('episodes') or []
            ep_nums = {
                ep.get('episode_number')
                for ep in episodes_meta
                if isinstance(ep.get('episode_number'), int)
            }

            if e not in ep_nums:
                log.debug(f"❌ S{s:02d}E{e:02d} v TMDb není – skip")
                continue

            # Filtrování streamů v bucketu
            filtered_streams = []
            for st in streams:
                name = st.get('name') or ''
                name_slug = _normalize_and_slugify(name)
                strict_match = strict_title_match(name, title_gate)

                # A) Primární slug-match (přísný)
                is_slug_match = any(vs and vs in name_slug for vs in valid_slugs)

                # B) Měkký fallback
                if not is_slug_match and not aggressive_mode:
                    clean = name.replace('.', ' ')
                    has_ep_hint = bool(
                        re.search(r'(?i)\bS\d{1,2}\s*E\d{1,3}\b', clean) or
                        re.search(r'(?i)\b\d{1,2}\s*[x×]\s*\d{1,3}\b', clean) or
                        re.search(r'(?i)\b(sezona|série|řada)\s*\d{1,2}.*(díl|epizoda|ep)\s*\d{1,3}\b', clean)
                    )
                    file_tokens = set(_tokens(name))
                    token_ok = len(series_tokens.intersection(file_tokens)) >= 2
                    if has_ep_hint and token_ok:
                        is_slug_match = True

                if aggressive_mode:
                    is_slug_match = strict_match

                if not is_slug_match:
                    if aggressive_mode:
                        log.debug(f"[SeriesFilter] Aggressive reject title family: {name}")
                    continue

                # C) Kontrola roku
                year_match = re.search(r'\b(19|20)\d{2}\b', name)
                if year_match and tmdb_year:
                    if int(year_match.group(0)) != int(tmdb_year):
                        log.debug(f"❌ Rok mismatch {year_match.group(0)} vs {tmdb_year}: {name}")
                        continue

                filtered_streams.append(st)

            if filtered_streams:
                valid_buckets[(s, e)] = filtered_streams

        except Exception as ex:
            log.warning(f"[SeriesFilter] Chyba při validaci S{s}E{e}: {ex}")
            continue

    log.info(f"[SeriesFilter] Dokončen: {len(valid_buckets)} validních položek.")
    return valid_buckets
