# -*- coding: utf-8 -*-
"""
Playlist indexer: M3U -> JSON (s TMDb ID) + rychlé lookupy.
- Parsuje M3U (bez GUI) včetně #KODIPROP a #EXTVLCOPT
- Normalizuje názvy (casefold + unidecode + ořez závorek)
- Přiřazuje tmdb_id (lokální TMDb vyhledávání; API key z nastavení)
- Stahuje základní TMDb detaily (poster_path, plot, lokalizovaný title)
- Ukládá/načítá index (JSON) do profilu doplňku
- Najde nejlepší shodu (tmdb_id -> URL, nebo title+year)
"""
import os
import re
import json
import time
import xbmc
import xbmcgui
import xbmcaddon
import xbmcvfs
from resources.lib.utils.log_utils import get_logger

log = get_logger()
ADDON = xbmcaddon.Addon('plugin.video.mmirousek_v3')
ADDON_ID = ADDON.getAddonInfo('id')
ADDON_NAME = ADDON.getAddonInfo('name')
# ---- TMDb konstanta ----------------------------------------------------------
TMDB_API_URL = "https://api.themoviedb.org/3"
# ---- unidecode normalizace ---------------------------------------------------
def get_playlist_path():
    addon_path = ADDON.getAddonInfo("path")
    return xbmcvfs.translatePath(addon_path + "/resources/media/playlist.m3u")

try:
    import unidecode
    def _strip_diacritics(s): return unidecode.unidecode(s or '')
except Exception:
    def _strip_diacritics(s): return s or ''
# Cesty / I/O
def _profile_root():
    p = xbmcvfs.translatePath(ADDON.getAddonInfo('profile'))
    if not p.endswith(('/', '\\')):
        p += '/'
    xbmcvfs.mkdirs(p)
    return p
def index_json_path() -> str:
    """Kam uložit playlist index JSON."""
    return _profile_root() + 'playlist_index.json'
def _read_text(path: str) -> str:
    f = xbmcvfs.File(path, 'r')
    try:
        raw = f.read()
    finally:
        try:
            f.close()
        except Exception:
            pass
    if isinstance(raw, bytes):
        raw = raw.decode('utf-8', 'ignore')
    return raw or ''

def _write_text(path: str, text: str) -> None:
    f = xbmcvfs.File(path, 'w')
    try:
        b = bytearray(text, 'utf-8')
        f.write(b)
    finally:
        try:
            f.close()
        except Exception:
            pass
# M3U parsování (včetně #KODIPROP a #EXTVLCOPT)
# #EXTINF:-1 tvg-id="..." tvg-name="..." tvg-logo="..." group-title="Filmy",Název (2019) CZ
M3U_EXTINF_RE = re.compile(r'#EXTINF[^\n]*?,(?P<title>.*)')
# key="value"
ATTR_PAIR_RE = re.compile(r'(\w+)\s*=\s*"([^"]*)"')

def parse_m3u(filepath: str) -> list:
    """
    Načte M3U (lokální cesta) a vrátí list položek:
    {
      title_raw, m3u_url, logo, group,
      kodiprop: { ... },
      vlcopt:   { ... }
    }
    """
    items = []
    if not filepath:
        return items

    if not os.path.isfile(filepath):
        log.error(f"[M3U-INDEX] Soubor nenalezen: {filepath}")
        return items
    try:
        with open(filepath, 'r', encoding='utf-8', errors='ignore') as f:
            lines = f.readlines()
    except Exception as e:
        log.error(f"[M3U-INDEX] Chyba při čtení M3U: {e}")
        return items
    i = 0
    n = len(lines)
    while i < n:
        line = lines[i].strip()
        if line.startswith('#EXTINF'):
            info_line = line
            url_line = ''
            props = {}      # #KODIPROP:inputstream.adaptive.manifest_type=hls
            vlcopts = {}    # #EXTVLCOPT:http-user-agent=...

            # Titulek z EXTINF
            title = ''
            m_title = M3U_EXTINF_RE.search(info_line)
            if m_title:
                title = (m_title.group('title') or '').strip()

            # Atributy key="value" uvnitř EXTINF
            logo = None
            group = None
            for m in ATTR_PAIR_RE.finditer(info_line):
                key = (m.group(1) or '').lower()
                val = (m.group(2) or '').strip()
                if key == 'tvg-logo':
                    logo = val
                elif key == 'group-title':
                    group = val

            # Sesbírat mezilehlé řádky až po URL
            j = i + 1
            while j < n:
                s = (lines[j] or '').strip()
                if not s:
                    j += 1
                    continue
                if s.startswith('#EXTINF'):
                    # Začíná další položka -> bez URL (poškozené M3U)
                    break
                if s.startswith('#KODIPROP:'):
                    # #KODIPROP:key=value
                    try:
                        kv = s.split(':', 1)[1]
                        k, v = kv.split('=', 1)
                        props[(k or '').strip()] = (v or '').strip()
                    except Exception:
                        pass
                elif s.startswith('#EXTVLCOPT:'):
                    # #EXTVLCOPT:key=value
                    try:
                        kv = s.split(':', 1)[1]
                        k, v = kv.split('=', 1)
                        vlcopts[(k or '').strip()] = (v or '').strip()
                    except Exception:
                        pass
                elif s.startswith('#'):
                    # jiný komentář – přeskočit
                    pass
                else:
                    # Předpokládáme URL
                    url_line = s
                    break
                j += 1

            if url_line:
                items.append({
                    'title_raw': title or '???',
                    'm3u_url': url_line,
                    'logo': logo,
                    'group': group,
                    'kodiprop': props,
                    'vlcopt': vlcopts
                })
            i = j + 1 if j >= i else i + 1
        else:
            i += 1

    log.info(f"[M3U-INDEX] Načteno položek: {len(items)}")
    return items
# Normalizace názvu
PARENS_RE = re.compile(r'[\(\[\{].*?[\)\]\}]')   # text v závorkách pryč
NON_ALNUM_RE = re.compile(r'[^a-z0-9]+')         # nealfanum. -> mezera
YEAR_RE = re.compile(r'(19|20)\d{2}')

def normalize_title(s: str) -> str:
    """
    casefold + odmazání diakritiky + smazat text v závorkách + nealfanumerika -> mezera
    """
    s = _strip_diacritics((s or '').casefold())
    s = PARENS_RE.sub(' ', s)
    s = NON_ALNUM_RE.sub(' ', s)
    return ' '.join(s.split()).strip()
def guess_year_from_title(s: str):
    """
    Heuristika: rok ve tvaru (YYYY) nebo '... YYYY ...'
    """
    if not s:
        return None
    m = YEAR_RE.search(s)
    if m:
        try:
            y = int(m.group(0))
            if 1900 <= y <= 2100:
                return y
        except Exception:
            pass
    return None
# TMDb lookup (lokální util)
def _tmdb_api_key():
    k = ADDON.getSetting('tmdb_api_key') or ''
    return (k or '').strip() or None

def _tmdb_search_local(title: str, year: int = None, is_tv: bool = False):
    """
    Vrátí tmdb_id pro zadaný název/rok. Použije lokální HTTP dotaz na TMDb.
    Pořadí pokusů: (cs-CZ, s rokem) -> (cs-CZ, bez roku) -> (en-US, s rokem) -> (en-US, bez roku).
    """
    import requests
    api_key = _tmdb_api_key()
    if not api_key or not (title or '').strip():
        return None

    endpoint = f"{TMDB_API_URL}/search/{'tv' if is_tv else 'movie'}"

    def _once(lang: str, use_year: bool):
        params = {
            'api_key': api_key,
            'query': title,
            'include_adult': 'false',
            'language': lang
        }
        if use_year and year:
            params['first_air_date_year' if is_tv else 'year'] = int(year)
        try:
            r = requests.get(endpoint, params=params, timeout=10)
            r.raise_for_status()
            results = (r.json() or {}).get('results') or []
            if results:
                rid = int(results[0].get('id') or 0)
                return rid or None
        except Exception as e:
            log.warning(f"[M3U-INDEX] TMDb search error: {e}")
        return None

    for lang in ('cs-CZ', 'en-US'):
        for use_year in (True, False):
            tmdb_id = _once(lang, use_year)
            if tmdb_id:
                return tmdb_id
    return None

def _tmdb_detail(tmdb_id: int, is_tv: bool, lang: str):
    """Načte detail (CZ/EN) a vrátí JSON nebo None."""
    import requests
    api_key = _tmdb_api_key()
    if not api_key or not tmdb_id:
        return None
    endpoint = f"{TMDB_API_URL}/{'tv' if is_tv else 'movie'}/{int(tmdb_id)}"
    try:
        r = requests.get(endpoint, params={'api_key': api_key, 'language': lang}, timeout=10)
        r.raise_for_status()
        return r.json() or {}
    except Exception as e:
        log.warning(f"[M3U-INDEX] TMDb detail error: {e}")
        return None
# TMDb enrich + build index
def attach_tmdb_id(items: list, is_tv: bool = False, progress_cb=None) -> list:
    """
    Pro každý item se pokusí dohledat tmdb_id a obohatit o TMDb detaily:
    - title_norm, year
    - tmdb_id
    - poster_path (pro artwork)
    - plot (CZ nebo EN)
    - display_title (lokalizovaný název, jinak původní title_raw)
    """
    out = []
    total = len(items) or 1
    for idx, it in enumerate(items, start=1):
        title_raw = it.get('title_raw') or '???'
        norm = normalize_title(title_raw)
        year = guess_year_from_title(title_raw) if not is_tv else None

        # 1) Najít tmdb_id (cs/en + rok fallback)
        tmdb_id = None
        try:
            tmdb_id = _tmdb_search_local(title_raw, year, is_tv=is_tv)
        except Exception as e:
            log.warning(f"[M3U-INDEX] TMDb search error for '{title_raw}': {e}")

        poster_path = None
        plot = None
        localized_title = None

        # 2) Pokud máme ID a klíč, stáhnout detail (CZ -> EN fallback)
        if tmdb_id and _tmdb_api_key():
            d_cz = _tmdb_detail(tmdb_id, is_tv, 'cs-CZ') or {}
            d_en = None
            # vyzobat hodnoty s fallbackem
            poster_path = d_cz.get('poster_path') or None
            plot = d_cz.get('overview') or None
            name_key = 'name' if is_tv else 'title'
            localized_title = d_cz.get(name_key) or d_cz.get('title') or d_cz.get('name')
            if not (poster_path and plot and localized_title):
                d_en = _tmdb_detail(tmdb_id, is_tv, 'en-US') or {}
                poster_path = poster_path or d_en.get('poster_path') or None
                plot = plot or d_en.get('overview') or None
                localized_title = localized_title or d_en.get(name_key) or d_en.get('title') or d_en.get('name')

        out.append({
            'title_raw': title_raw,
            'title_norm': norm,
            'year': year,
            'tmdb_id': int(tmdb_id) if tmdb_id else 0,
            'media_type': 'tv' if is_tv else 'movie',
            'm3u_url': it.get('m3u_url'),
            'logo': it.get('logo'),
            'group': it.get('group'),
            'kodiprop': it.get('kodiprop') or {},   # ponecháme i pro přehrávač (volitelně)
            'vlcopt': it.get('vlcopt') or {},
            'poster_path': poster_path,             # <-- NOVĚ
            'plot': plot,                           # <-- NOVĚ
            'display_title': localized_title or title_raw,  # lokalizovaný název, pokud je
            'confidence': 1.0 if tmdb_id else 0.0
        })

        if progress_cb:
            try:
                pct = int(100.0 * idx / total)
                progress_cb(pct, f"TMDb párování {idx}/{total} – {title_raw}")
            except Exception:
                pass

    return out

def build_index(items_with_ids: list, source_path: str) -> dict:
    """
    Připraví strukturu {meta, items} pro JSON + meta informace.
    """
    meta = {
        'source_path': source_path or '',
        'source_mtime': int(os.path.getmtime(source_path)) if source_path and os.path.exists(source_path) else 0,
        'build_time': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()),
        'count': len(items_with_ids or [])
    }
    return {'meta': meta, 'items': items_with_ids or []}

def save_index_json(index: dict, path: str = None) -> None:
    from resources.lib.database.metadata_db import db
    meta = index.get('meta', {})
    items = index.get('items', [])
    db.save_playlist_meta(meta)
    db.save_playlist_items(items)

def load_index_json(path: str = None) -> dict:
    from resources.lib.database.metadata_db import db
    meta = db.get_playlist_meta()
    if not meta or meta.get('count', 0) == 0:
        return {}
    # Není třeba načítat do paměti celý strom statisíců položek, lookup zařídí SQLite
    return {'meta': meta, 'items': []}

def needs_rebuild(m3u_path: str, index: dict) -> bool:
    try:
        if not (m3u_path and os.path.exists(m3u_path)):
            return False
        src_mtime = int(os.path.getmtime(m3u_path))
        meta = (index or {}).get('meta') or {}
        return int(meta.get('source_mtime') or 0) != src_mtime
    except Exception:
        return False

def rebuild_if_needed(m3u_path: str, is_tv: bool = False, force: bool = False, show_progress: bool = False) -> dict:
    """
    Pokud index chybí nebo je starý (nebo force=True), postaví nový a uloží to DB.
    """
    m3u_path = m3u_path or get_playlist_path()
    idx = load_index_json()
    if not force and idx and not needs_rebuild(m3u_path, idx):
        return idx

    items = parse_m3u(m3u_path)
    if not items:
        return {}

    dlg = xbmcgui.DialogProgress() if show_progress else None
    if dlg:
        dlg.create("M3U → SQLite (TMDb)", "Připravuji SQL Cache…")

    def _cb(pct, msg):
        if dlg:
            dlg.update(max(0, min(100, pct)), msg)

    with_ids = attach_tmdb_id(items, is_tv=is_tv, progress_cb=_cb)
    idx = build_index(with_ids, m3u_path)
    save_index_json(idx)

    if dlg:
        dlg.update(100, "Hotovo")
        dlg.close()

    log.info(f"[M3U-INDEX] Index překompilován a uložen (položek {idx['meta']['count']})")
    return idx

# Lookup (vyhledání v indexu - nově přes SQLite)
def find_best_match(index: dict, tmdb_id: int = 0, title: str = '', year: int = None):
    """
    Vrátí jednu nejlepší položku nebo None bez prohledávání pole v paměti:
    - provede optimalizovaný databázový dotaz do playlist_index.
    """
    from resources.lib.database.metadata_db import db
    norm = normalize_title(title or '')
    return db.search_playlist_index(tmdb_id=int(tmdb_id or 0), title_norm=norm, year=year)

