# -*- coding: utf-8 -*-
"""
UpdateEngine: orchestr smart refresh (UHD -> HD -> name-only -> fallback)
- Nedestruktivní chování: APPEND ve všech průchodech (A/B/C/D)
- UI vrstva (series_ui.py) volá jen tuto třídu; ta používá SearchEngine pro jednotlivé passy.
"""

import xbmc
import xbmcgui
from resources.lib.utils.log_utils import get_logger
from resources.lib.series.search_engine import SearchEngine

log = get_logger()


class UpdateEngine:
    def __init__(self, series_manager):
        """
        :param series_manager: Instance SeriesManager (persist, tmdb, helpery)
        """
        self.sm = series_manager
        self.se = SearchEngine(series_manager)

    def refresh_smart(
        self,
        series_name: str,
        api_function,
        token,
        query_candidates,
        *,
        max_streams: int = 10,
        filter_mode: str = 'standard',
        progress_label: str = None,
        target_season=None,
        target_episode=None,
    ):
        """
        Spustí víceprůchodovou aktualizaci:
          - Pass A: only_uhd=True (UHD/4K/HDR)   + update_policy='append'
          - Pass B: force_hd_only=True, skip_high_quality=True (1080p/720p, bez 2160p) + 'append'
          - Pass C: name_only=True (cílené doplnění chybějících S/E) + 'append'
          - Pass D (fallback/parita): opět name_only=True + 'append' (spouští se jen pokud C nic nenašlo)

        Všude se používá NEDSTRUKTIVNÍ politika `append`, aby se existující streamy nikdy nepřepisovaly —
        přiřadí se pouze nové kandidáty dopředu (SearchEngine dělá deduplikaci a ořez).

        :param series_name: Klíč záznamu v DB z URL (safe_name, typicky tmdb_<id>) — předává se do SearchEngine jako storage_key.
        :param api_function: callable pro Webshare API
        :param token: WST token
        :param query_candidates: list[str] — kandidátní názvy v pořadí priority (primary, CZ, EN)
        :param max_streams: int — horní limit počtu streamů na epizodu (po merge/append)
        :param filter_mode: str — 'standard' | 'aggressive' (předává se do SearchEngine)
        :param progress_label: Volitelný text do dialogu (zobrazený název); jinak series_name.
        :return: dict | None — poslední snapshot dat (series_data) nebo None, pokud nenašlo nic
        """
        if not query_candidates:
            log.info("Žádné query kandidáty — končím.")
            return None

        filter_mode = (filter_mode or 'standard').lower()
        if filter_mode not in ('standard', 'aggressive'):
            filter_mode = 'standard'
        mode_label = 'AGGRESSIVE' if filter_mode == 'aggressive' else 'STANDARD'
        dlg_title_name = (progress_label or '').strip() or series_name
        target_kwargs = {}
        target_label = ''
        if target_season is not None and target_episode is not None:
            target_kwargs = {
                'target_season': target_season,
                'target_episode': target_episode,
            }
            try:
                target_label = f" S{int(target_season):02d}E{int(target_episode):02d}"
            except (TypeError, ValueError):
                target_label = f" S{target_season}E{target_episode}"

        dlg = xbmcgui.DialogProgress()
        dlg.create('StreamManager', f"Aktualizuji (smart/{mode_label}) {dlg_title_name}{target_label}…")

        try:
            found_any = False
            data_snapshot = None

            # Definice průchodů — VŽDY nedestruktivní `update_policy='append'`
            passes = [
                ("UHD (4K/HDR)",
                 {"refresh": True, "only_uhd": True, "update_policy": 'append'},
                 max_streams),
                ("HD only (1080p + 720p)",
                 {"refresh": True, "force_hd_only": True, "skip_high_quality": True, "update_policy": 'append'},
                 max_streams),
            ]

            total_steps = max(1, len(passes) * len(query_candidates)) + 2  # + C + případně D
            step = 0

            # Pass A/B přes všechny query kandidáty
            for label, opts, mx in passes:
                for i, q in enumerate(query_candidates):
                    if dlg.iscanceled():
                        log.info("CANCELLED by user")
                        dlg.close()
                        return data_snapshot if found_any else None
                    step += 1
                    pct = int(step / total_steps * 100)
                    dlg.update(pct, f"[{mode_label}] {label}: {q}")
                    log.info(f"{label} – hledám podle '{q}' (policy=append, max_streams={mx})")

                    current = self.se.search_series(
                        q,
                        api_function,
                        token,
                        **opts,
                        max_streams=mx,
                        filter_mode=filter_mode,
                        storage_key=series_name,
                        **target_kwargs,
                    )

                    if current and current.get('seasons'):
                        found_any = True
                        data_snapshot = current  # poslední použitelný snapshot

            # Pass C: name-only cíleně (vezme první kandidát jako primární),
            # opět NEDSTRUKTIVNĚ (append)
            if not dlg.iscanceled():
                step += 1
                pct = int(step / total_steps * 100)
                dlg.update(pct, f"[{mode_label}] Name-only (SxxExx): cílené chybějící epizody")
                log.info(f"Cílené name-only na chybějící epizody (policy=append, max_streams={max_streams})")

                current = self.se.search_series(
                    query_candidates[0],
                    api_function,
                    token,
                    refresh=True,
                    name_only=True,
                    update_policy='append',
                    max_streams=max_streams,
                    filter_mode=filter_mode,
                    storage_key=series_name,
                    **target_kwargs,
                )
                if current and current.get('seasons'):
                    found_any = True
                    data_snapshot = current

            # Pass D: fallback/parita — pouze pokud dosud NIC nenašlo C ani A/B
            if not found_any and not dlg.iscanceled():
                step += 1
                pct = int(step / total_steps * 100)
                dlg.update(pct, f"[{mode_label}] Fallback: široké S/E dotazy (append)")
                log.info(f"Fallback: name-only (policy=append, max_streams={max_streams})")

                current = self.se.search_series(
                    query_candidates[0],
                    api_function,
                    token,
                    refresh=True,
                    name_only=True,
                    update_policy='append',
                    max_streams=max_streams,
                    filter_mode=filter_mode,
                    storage_key=series_name,
                    **target_kwargs,
                )
                if current and current.get('seasons'):
                    found_any = True
                    data_snapshot = current

            if found_any and data_snapshot:
                eps_with_streams = [
                    (s_k, e_k)
                    for s_k, s_data in data_snapshot.get('seasons', {}).items()
                    for e_k, e_data in (s_data or {}).items()
                    if e_k.isdigit() and e_data.get('streams')
                ]
                total_eps = len(eps_with_streams)
                total_seasons = len(set(s_k for s_k, e_k in eps_with_streams))
                log.info(f"Smart refresh dokončen: nalezeno {total_eps} epizod se streamy v {total_seasons} sezónách.")

            dlg.close()
            return data_snapshot if found_any else None

        except Exception as e:
            dlg.close()
            log.error(f"CHYBA: {e}")
            return None