# -*- coding: utf-8 -*-
"""Independent, strict judge of Webshare file names (no addon code imported).

parse(name) reads what a file *is*: SxxEyy, year, quality, CZ dub vs subtitles.
matches(parsed, case) says whether it is the requested movie / episode.
judge(rows, case) checks the top row against every valid candidate:
right title + episode/year, best available language tier, best quality there.
"""

import re
import unicodedata

QUALITY_RANK = {'4K': 5, '1080p': 4, '720p': 3, '480p': 2, '360p': 1, 'SD': 0}

# Language tiers, higher = preferred ("primárně CZ dabing, jinak titulky").
# Bare "CZ" on Webshare almost always means dubbed audio, so it shares the top tier.
# CZ subtitles beat SK dub (user decision 2026-09-29).
LANG_RANK = {'CZ_DUB': 5, 'CZ': 5, 'CZ_SUB': 4, 'SK_DUB': 3, 'SK_SUB': 2, 'OTHER': 0}

# Smallest believable file per quality (smaller = sample, trailer or broken encode)
MIN_SIZE_MB = {'movie': {'4K': 3000, '1080p': 1200, '720p': 600},
               'episode': {'4K': 700, '1080p': 250, '720p': 150}}


def norm(text):
    """Lowercase ASCII, separators to single spaces: 'Přátelé.S01E02' -> 'pratele s01e02'."""
    text = unicodedata.normalize('NFKD', text or '')
    text = ''.join(c for c in text if not unicodedata.combining(c)).lower()
    return re.sub(r'[^a-z0-9]+', ' ', text).strip()


_SE = [re.compile(r'\bs(\d{1,2}) ?e(\d{1,3})\b'),        # s01e02, s01 e02
       re.compile(r'\b(\d{1,2})x(\d{2,3})\b'),            # 1x02, 01x02
       re.compile(r'\bserie (\d{1,2}) dil (\d{1,3})\b')]  # serie 1 dil 2


def parse(name, size=0):
    n = norm(name)
    tokens = set(n.split())
    season = episode = None
    se_pos = None
    for pattern in _SE:
        m = pattern.search(n)
        if m:
            season, episode, se_pos = int(m.group(1)), int(m.group(2)), m.start()
            break
    years = [int(y) for y in re.findall(r'\b(19[2-9]\d|20[0-4]\d)\b', n)]

    if re.search(r'\b2160|\b(4k|uhd|uhdr|uhdtv)\b', n):
        quality = '4K'
    elif re.search(r'\b1080|\b(fhd|fullhd|full hd)\b', n):
        quality = '1080p'
    elif re.search(r'\b720 ?p', n) or ('hd' in tokens and not name.lower().endswith('.avi') and 'xvid' not in tokens):
        quality = '720p'
    elif re.search(r'\b(480|576) ?p', n):
        quality = '480p'
    elif re.search(r'\b360 ?p', n):
        quality = '360p'
    else:
        quality = 'SD'

    compact = n.replace(' ', '')
    has_cz = bool(tokens & {'cz', 'czech', 'cesky', 'cestina', 'czaudio', 'czdab', 'czdabing',
                            'cztit', 'czsub', 'czen', 'czsk', 'cze'}) or 'czaudio' in compact
    has_sk = bool(tokens & {'sk', 'slovak', 'slovensky', 'skdab', 'sktit', 'sksub'})
    sub = bool(re.search(r'\b(tit|titulky|titulkama|sub|subs|subti|subtitles|cztit|czsub|sktit|sksub)\b', n))
    dub = bool(re.search(r'\b(dab|dabing|dabingem|dub|dubbing|czdab|czdabing|czdub|skdab|skdub|dabovane|audio|czaudio)\b', n)) \
        or 'czaudio' in compact or 'cesky dabing' in n
    # "cz tit" / "cz sub" alone = subtitles; "dab" anywhere wins (e.g. "CZ dab + CZ tit")
    if has_cz and dub:
        lang = 'CZ_DUB'
    elif has_cz and sub and not dub:
        lang = 'CZ_SUB'
    elif has_cz:
        lang = 'CZ'
    elif has_sk and dub:
        lang = 'SK_DUB'
    elif has_sk and sub:
        lang = 'SK_SUB'
    elif has_sk:
        lang = 'SK_DUB'
    else:
        lang = 'OTHER'
    try:
        size = int(size or 0)
    except (TypeError, ValueError):
        size = 0
    return {'norm': n, 'season': season, 'episode': episode, 'se_pos': se_pos, 'years': years,
            'quality': quality, 'lang': lang, 'size_mb': size // (1024 * 1024),
            'ext': name.rsplit('.', 1)[-1].lower() if '.' in name else ''}


def _title_variants(case):
    out = []
    for title in (case.get('title'), case.get('original_title')):
        t = norm(title)
        if t and t not in out:
            out.append(t)
            if t.startswith('the '):
                out.append(t[4:])
    return out


_TAGS = re.compile(r'\b(19[2-9]\d|20[0-4]\d|\d{3,4}[pi]|4k|uhd|fhd|hd|cz|sk|en|eng|czech|bluray|bdrip|brrip|'
                   r'webrip|web|dvdrip|hdtv|x264|x265|hevc|xvid|remux|dabing|dab|tit|titulky|multi)\b')


def _title_only(p, variants):
    """The part before SxxEyy (episode) or before the first year/tag (movie) is only title variants."""
    n = p['norm']
    if p['se_pos'] is not None:
        head = n[:p['se_pos']]
    else:
        m = _TAGS.search(n, 1)
        head = n[:m.start()] if m else n
    head = ' ' + re.sub(r'^(\d{1,3} )+', '', head.strip()) + ' '  # "01 pratele ..."
    hit = False
    for v in sorted(variants, key=len, reverse=True):
        if ' ' + v + ' ' in head:
            head, hit = head.replace(' ' + v + ' ', ' '), True
    return hit and not [w for w in head.split() if w not in ('the', 'a')]


def matches(p, case):
    """(ok, reason). Episode: only the title before an exact SxxEyy. Movie: only the title before year/tags,
    year fits, no SxxEyy."""
    variants = _title_variants(case)
    if not _title_only(p, variants):
        return False, 'title'
    if case['type'] == 'episode':
        if (p['season'], p['episode']) != (case['season'], case['episode']):
            return False, 'episode'
        return True, ''
    if p['season'] is not None:
        return False, 'is-episode'
    year = case.get('year')
    if year and p['years'] and not any(abs(y - int(year)) <= 1 for y in p['years']):
        return False, 'year'
    return True, ''


def suspicious_size(p, kind):
    floor = MIN_SIZE_MB[kind].get(p['quality'])
    return bool(floor and p['size_mb'] and p['size_mb'] < floor)


def judge(rows, case, preferred=None):
    """rows: [{'name','size',...}] in shown order. Returns verdict dict for the top row.
    preferred: quality from the 'Preferred quality' setting (None = best available)."""
    kind = case['type']
    parsed = [dict(parse(r.get('name', ''), r.get('size')), row=r) for r in rows]
    valid = [p for p in parsed if matches(p, case)[0]]
    if not rows:
        return {'verdict': 'EMPTY', 'why': 'no results shown', 'valid': 0}
    if not valid:
        return {'verdict': 'NO_VALID', 'why': 'no result is the right title/episode', 'valid': 0}
    top = parsed[0]
    ok, reason = matches(top, case)
    if not ok:
        return {'verdict': 'WRONG', 'why': 'top is wrong ' + reason, 'valid': len(valid)}
    sane = [p for p in valid if not suspicious_size(p, kind)] or valid
    best_lang = max(LANG_RANK[p['lang']] for p in sane)
    if LANG_RANK[top['lang']] < best_lang:
        want = [k for k, v in LANG_RANK.items() if v == best_lang][0]
        return {'verdict': 'LANG', 'why': 'top {} but {} exists'.format(top['lang'], want), 'valid': len(valid)}
    tier = [p for p in sane if LANG_RANK[p['lang']] == best_lang]
    if tier and preferred and any(p['quality'] == preferred for p in tier):
        if top['quality'] != preferred:
            return {'verdict': 'QUALITY', 'why': 'top {} but preferred {} exists'.format(top['quality'], preferred),
                    'valid': len(valid)}
    elif tier:
        below = [p for p in tier if not preferred or QUALITY_RANK[p['quality']] <= QUALITY_RANK[preferred]] or tier
        best_q = max(QUALITY_RANK[p['quality']] for p in below)
        if QUALITY_RANK[top['quality']] < best_q:
            want = [k for k, v in QUALITY_RANK.items() if v == best_q][0]
            return {'verdict': 'QUALITY', 'why': 'top {} but {} exists'.format(top['quality'], want),
                    'valid': len(valid)}
    if suspicious_size(top, kind):
        return {'verdict': 'SIZE', 'why': 'top {} only {} MB'.format(top['quality'], top['size_mb']),
                'valid': len(valid)}
    return {'verdict': 'OK', 'why': '', 'valid': len(valid)}


# Chip values the dialog shows vs what the name says
_CHIP_LANG = {'CZ_DUB': ('CZ dabing', 'CZ', 'CZ Dab', 'MultiDub', 'CZ+EN'),
              'CZ': ('CZ', 'CZ dabing', 'CZ Dab', 'CZ+EN', 'MultiDub'),
              'CZ_SUB': ('CZ titulky',), 'SK_DUB': ('SK dabing', 'SK'), 'SK_SUB': ('SK titulky',),
              'OTHER': ('N/A', 'EN', '', 'MultiDub')}
_CHIP_QUALITY = {'4K': ('4K', 'REMUX'), '1080p': ('1080p',), '720p': ('720p', 'HD'),
                 '480p': ('480p',), '360p': ('360p',), 'SD': ('SD', 'N/A', '')}


def chip_mismatches(name, size, quality_chip, lang_chip):
    p = parse(name, size)
    issues = []
    if quality_chip not in _CHIP_QUALITY[p['quality']]:
        issues.append('quality chip {} vs {}'.format(quality_chip or '-', p['quality']))
    if lang_chip not in _CHIP_LANG[p['lang']]:
        issues.append('lang chip {} vs {}'.format(lang_chip or '-', p['lang']))
    return issues
