# -*- coding: utf-8 -*-
"""
Series logic: byznys logika, synchronizace a složitější datové operace.
"""
import json
from resources.lib.utils.log_utils import get_logger
from resources.lib.database.metadata_db import db
from resources.lib.series.series_helpers import _derive_latest_episode_timestamp

log = get_logger()

def is_series_completed(series_data: dict) -> bool:
    """Vrátí True, pokud jsou všechny sezóny označeny jako zhlédnuté."""
    try:
        if not isinstance(series_data, dict): return False
        seasons = series_data.get('seasons') or {}
        season_state = series_data.get('season_state') or {}
        if not seasons: return False
        for s_key in seasons.keys():
            st = season_state.get(str(s_key)) or {}
            if not st.get('watched', False): return False
            if st.get('watched_count') != st.get('total'): return False
        return True
    except: return False

def is_series_started(series_data: dict) -> bool:
    """Vrátí True, pokud má seriál alespoň jednu viděnou epizodu."""
    try:
        if not isinstance(series_data, dict): return False
        season_state = series_data.get('season_state') or {}
        for st in season_state.values():
            if st.get('watched_count', 0) > 0 or st.get('watched', False):
                return True
        return False
    except: return False

def sync_series_with_sql(series_manager, series_name=None):
    """Synchronizuje JSON seriálů se stavem v SQL (Trakt/SQLite)."""
    log.info(f"[SeriesLogic] Synchronizace JSON <-> SQL" + (f" pro: {series_name}" if series_name else ""))
    
    all_series = [{"name": series_name}] if series_name else series_manager.get_all_series()
    count_updated = 0

    for entry in all_series:
        s_name = entry.get("safe_name") or entry["name"]
        data = series_manager.load_series_data(s_name)
        if not data: continue

        tmdb_id = (data.get("tmdb") or {}).get("id")
        if not tmdb_id: continue

        sql_row = db.get_by_tmdb_id(tmdb_id)
        if not sql_row: continue

        trakt_full = sql_row.get("trakt_full_data")
        if not trakt_full: continue

        try:
            trakt_obj = json.loads(trakt_full)
        except: continue

        trakt_map = {}
        for s in trakt_obj.get("seasons", []):
            sn = s.get("number")
            for ep in s.get("episodes", []):
                en = ep.get("number")
                lwa = ep.get("last_watched_at")
                if sn is not None and en is not None and lwa:
                    trakt_map[(sn, en)] = lwa

        changed = False
        seasons_dict = data.get("seasons") or {}
        for s_key, season in seasons_dict.items():
            try: s_num = int(s_key)
            except: continue
            for e_key, ep in season.items():
                try: e_num = int(e_key)
                except: continue
                lwa = trakt_map.get((s_num, e_num))
                if not lwa: continue
                if not ep.get("watched"):
                    ep["watched"] = True
                    ep["progress"] = 100.0
                    changed = True
                if ep.get("last_watched_at") != lwa:
                    ep["last_watched_at"] = lwa
                    changed = True

        for skey in seasons_dict.keys():
            # series_manager._recalc_season_state normally modifies 'data' directly
            # We don't want to recount 'changed' just for this if the episodes didn't change,
            # but wait, recalc might change watched count if it wasn't accurate.
            # However, if watched didn't change, watched_count didn't change.
            series_manager._recalc_season_state(data, skey)

        old_completed = data.get("series_completed")
        all_watched = True if seasons_dict else False
        for state in data.get("season_state", {}).values():
            if not state.get("watched"):
                all_watched = False
                break
        
        if old_completed != all_watched:
            data["series_completed"] = all_watched
            changed = True
            
        if changed:
            series_manager._save_series_data(s_name, data)
            count_updated += 1
    
    log.info(f"[SeriesLogic] Hotovo. Aktualizováno {count_updated} seriálů.")

def get_next_episodes_list(series_manager):
    """Vrátí seznam Next-up epizod pro rozkoukané seriály."""
    log.info("[SeriesLogic] Hledám následující epizody.")
    series_name_list = series_manager.get_all_series()
    
    all_series_data = []
    for s in series_name_list:
        data = series_manager.load_series_data(s.get('safe_name') or s['name'])
        if data and data.get('seasons'):
            data['name'] = s['name']
            data['safe_name'] = s.get('safe_name') or s['name']
            all_series_data.append(data)

    in_progress = []
    for d in all_series_data:
        # Next-Up má používat stejné vstupní kritérium jako sekce "Rozkoukané".
        is_ip = (not d.get('completed', False)) and is_series_started(d)
        ts = d.get('last_watched_at_utc') or d.get('last_watched_at') or _derive_latest_episode_timestamp(d)
        if is_ip and ts:
            d['_nextup_sort_key'] = ts
            in_progress.append(d)

    in_progress.sort(key=lambda x: x.get('_nextup_sort_key', '1970'), reverse=True)

    next_episodes = []
    for data in in_progress:
        found_ep = None
        sorted_seasons = sorted(data.get('seasons', {}).items(), key=lambda item: int(item[0]) if item[0].isdigit() else 9999)
        for s_key, season_data in sorted_seasons:
            if not season_data: continue
            sorted_eps = sorted(season_data.items(), key=lambda item: int(item[0]) if item[0].isdigit() else 9999)
            for e_key, ep in sorted_eps:
                if not ep.get('watched', False):
                    found_ep = ep
                    ep_data = found_ep.copy()
                    ep_data['series_name'] = data.get('safe_name') or data.get('name')
                    ep_data['display_name'] = data.get('name')
                    ep_data['season_num'] = int(s_key) if s_key.isdigit() else s_key
                    ep_data['episode_num'] = int(e_key) if e_key.isdigit() else e_key
                    next_episodes.append(ep_data)
                    break
            if found_ep: break
    
    log.info(f"[SeriesLogic] Nalezeno {len(next_episodes)} epizod.")
    return next_episodes

def validate_all_streams(series_manager, series_name, token, api_fn):
    """Validuje existenci streamů na Webshare."""
    import time, xbmcgui
    from xml.etree import ElementTree as ET

    data = series_manager.load_series_data(series_name)
    if not data: return {"ok": 0, "invalid": 0, "errors": [], "rescan": []}

    ok_count, invalid_count, rescan_eps = 0, 0, []
    dlg = xbmcgui.DialogProgress()
    dlg.create("Kontrola streamů", f"Seriál: {series_name}")
    
    streams_to_check = []
    for s_k, season in data.get("seasons", {}).items():
        for e_k, ep in season.items():
            for st in ep.get("streams", []):
                streams_to_check.append((s_k, e_k, ep, st))

    total = len(streams_to_check)
    for i, (s_k, e_k, ep, st) in enumerate(streams_to_check):
        if dlg.iscanceled(): break
        ident = st.get("ident")
        dlg.update(int((i/total)*100), f"S{s_k}E{e_k} • Zkontrolováno: {i}/{total}")

        try:
            resp = api_fn("file_info", {"ident": ident, "wst": token})
            xml = ET.fromstring(resp.content)
            if xml.findtext("status") == "OK":
                ok_count += 1
            else:
                invalid_count += 1
                if st in ep.get("streams", []):
                    ep["streams"].remove(st)
                    if (s_k, e_k) not in rescan_eps: rescan_eps.append((s_k, e_k))
        except:
            invalid_count += 1

        time.sleep(0.17)

    series_manager._save_series_data(series_name, data)
    dlg.close()
    return {"ok": ok_count, "invalid": invalid_count, "rescan": rescan_eps, "total": total}
