# wcs/ai/ProgressManager.py
"""
Centrální modul pro správu progressu sledování v MyTV.
Zapouzdřuje čtení/zápis progressu a inteligentní cache invalidaci
pomocí fingerprint mechanismu.
"""

import hashlib
import json
import xbmc

from wcs.ai import ChannelHistory


def get_progress(channel_id, series_id):
    """Vrátí aktuální progress seriálu v kanálu.
    
    Args:
        channel_id: ID kanálu
        series_id: TMDb ID seriálu
    
    Returns:
        tuple: (season, episode) nebo (1, 0) pokud neexistuje
    """
    return ChannelHistory.get_series_progress(channel_id, series_id)


def update_progress(channel_id, series_id, season, episode):
    """Aktualizuje progress seriálu v kanálu.
    
    Args:
        channel_id: ID kanálu
        series_id: TMDb ID seriálu
        season: Číslo sezóny
        episode: Číslo epizody
    """
    ChannelHistory.update_series_progress(channel_id, series_id, season, episode, manual=True)






def compute_progress_fingerprint(channel_id, series_list):
    """Vypočítá fingerprint aktuálního progressu všech seriálů v kanálu.
    
    Fingerprint je MD5 hash seřazených progress dat. Pokud se progress
    změní (sledování, editace), změní se i fingerprint.
    
    Args:
        channel_id: ID kanálu
        series_list: Seznam seriálů v kanálu (list of dicts s 'id')
    
    Returns:
        str: MD5 hash progressu
    """
    progress_data = {}
    for series in series_list:
        series_id = str(series.get('id', ''))
        if series_id:
            season, episode = ChannelHistory.get_series_progress(channel_id, series_id)
            progress_data[series_id] = (season, episode)
    
    # Seřadit pro deterministický výstup
    sorted_data = sorted(progress_data.items())
    fingerprint_str = json.dumps(sorted_data, sort_keys=True)
    return hashlib.md5(fingerprint_str.encode('utf-8')).hexdigest()


def save_progress_fingerprint(channel_id, series_list, cache):
    """Vypočítá a uloží fingerprint progressu pro kanál.
    
    Volat po uložení program list cache.
    
    Args:
        channel_id: ID kanálu
        series_list: Seznam seriálů v kanálu
        cache: CacheManager instance
    """
    fingerprint = compute_progress_fingerprint(channel_id, series_list)
    cache_key = f"progress_fp_{channel_id}"
    # Bez TTL -- fingerprint platí dokud se nezmění
    cache.set(cache_key, fingerprint, ttl_seconds=30 * 24 * 3600)


def is_cache_stale(channel_id, series_list, cache):
    """Zjistí, zda je program list cache zastaralá (progress se změnil).
    
    Porovná uložený fingerprint s aktuálním. Pokud se liší,
    cache je zastaralá a měla by se invalidovat.
    
    Args:
        channel_id: ID kanálu
        series_list: Seznam seriálů v kanálu
        cache: CacheManager instance
    
    Returns:
        bool: True pokud je cache zastaralá nebo neexistuje fingerprint
    """
    # Pokud neexistuje program list cache, není co invalidovat
    program_cache_key = f"program_list_{channel_id}"
    if not cache.get(program_cache_key):
        return False
    
    # Pokud nemáme uložený fingerprint, cache je zastaralá (první spuštění)
    fp_key = f"progress_fp_{channel_id}"
    saved_fp = cache.get(fp_key)
    if not saved_fp:
        return True
    
    # Porovnat s aktuálním fingerprintem
    current_fp = compute_progress_fingerprint(channel_id, series_list)
    return current_fp != saved_fp


def invalidate_stale_caches(channels, cache):
    """Invaliduje program list cache jen pro kanály kde se progress změnil.
    
    Pro každý kanál porovná fingerprint -- pokud se progress nezměnil,
    cache zůstane (rychlý start). Pokud se změnil, cache se invaliduje
    (správný program list).
    
    Args:
        channels: Seznam kanálů (objekty s .id a .series_list)
        cache: CacheManager instance
    
    Returns:
        int: Počet invalidovaných caches
    """
    invalidated = 0
    
    for channel in channels:
        channel_id = channel.id
        series_list = channel.series_list if hasattr(channel, 'series_list') else []
        
        if not series_list:
            continue
        
        if is_cache_stale(channel_id, series_list, cache):
            program_key = f"program_list_{channel_id}"
            cache.delete(program_key)
            # Smazat i starý fingerprint (nový se vytvoří po reload)
            fp_key = f"progress_fp_{channel_id}"
            cache.delete(fp_key)
            invalidated += 1
            xbmc.log(
                f"[MyTV] Progress changed for channel {channel_id} - cache invalidated",
                xbmc.LOGINFO
            )
    
    if invalidated == 0:
        xbmc.log("[MyTV] All program caches are fresh (no progress changes)", xbmc.LOGINFO)
    
    return invalidated


def invalidate_program_cache(channel_id, cache):
    """Vynutí invalidaci program list cache pro konkrétní kanál.
    
    Používat po editaci progressu (edit progress dialog).
    
    Args:
        channel_id: ID kanálu
        cache: CacheManager instance
    """
    program_key = f"program_list_{channel_id}"
    fp_key = f"progress_fp_{channel_id}"
    cache.delete(program_key)
    cache.delete(fp_key)
    xbmc.log(f"[MyTV] Force-invalidated cache for channel {channel_id}", xbmc.LOGINFO)
