# wcs/ai/ChannelHistory.py
"""
Správa historie sledování pro jednotlivé MyTV/MyCinema kanály.
Každý kanál má vlastní JSON soubor s progressem seriálů/filmů.

Supported channel_type values:
- 'tv' (default): MyTV channels with series (episodes progress)
- 'cinema': MyCinema channels with movies (watched status)
"""

import os
import json
import tempfile
import xbmc
import xbmcvfs
import xbmcaddon


def _get_history_dir(channel_type='tv'):
    """
    Vrátí cestu k adresáři s historiemi kanálů.
    
    Args:
        channel_type: 'tv' pro MyTV, 'cinema' pro MyCinema
    """
    profile = xbmcvfs.translatePath(xbmcaddon.Addon().getAddonInfo('profile'))
    if channel_type == 'cinema':
        history_dir = os.path.join(profile, 'mycinema_history')
    else:
        history_dir = os.path.join(profile, 'mytv_history')
    if not os.path.exists(history_dir):
        xbmcvfs.mkdirs(history_dir)
    return history_dir


def _get_history_file(channel_id, channel_type='tv'):
    """Vrátí cestu k JSON souboru historie pro daný kanál."""
    return os.path.join(_get_history_dir(channel_type), f'{channel_id}.json')


def _shared(channel_type='tv'):
    """wcs/library2/shared.py when the library store speaks for the channels of this type, else None."""
    try:
        from wcs.library2 import shared
        return shared if shared.active('cinema' if channel_type == 'cinema' else 'tv') else None
    except Exception as exc:
        xbmc.log(f'[MyTV] Shared progress unavailable: {exc}', xbmc.LOGWARNING)
        return None


def load_channel_history(channel_id, channel_type='tv'):
    """
    Načte historii sledování pro daný kanál (vždy soubor kanálu, i ve společném režimu).
    
    Args:
        channel_id: ID kanálu
        channel_type: 'tv' pro MyTV, 'cinema' pro MyCinema
    
    Returns:
        dict: Pro TV: {series_id: {"season": int, "episode": int}}
              Pro Cinema: {movie_id: {"watched": bool}}
    """
    file_path = _get_history_file(channel_id, channel_type)
    if not os.path.exists(file_path):
        return {}
    
    try:
        with open(file_path, 'r', encoding='utf-8') as f:
            return json.load(f)
    except (IOError, json.JSONDecodeError) as e:
        log_prefix = '[MyCinema]' if channel_type == 'cinema' else '[MyTV]'
        xbmc.log(f'{log_prefix} Error loading channel history {channel_id}: {e}', xbmc.LOGWARNING)
        return {}


def _history_changed(channel_type):
    """History affects local channel rows, not the cinema recommendation sources."""
    try:
        from wcs.skin.refresh import changed
        changed({'widget_mycinema_channels'} if channel_type == 'cinema' else {
            'widget_mytv_channels', 'widget_mytv_next'})
    except Exception as exc:
        xbmc.log(f'[Milionář Skin] Channel history refresh failed: {exc}', xbmc.LOGWARNING)


def save_channel_history(channel_id, history, channel_type='tv'):
    """
    Uloží historii sledování pro daný kanál.
    
    Args:
        channel_id: ID kanálu
        history: dict s historií
        channel_type: 'tv' pro MyTV, 'cinema' pro MyCinema
    """
    file_path = _get_history_file(channel_id, channel_type)
    if load_channel_history(channel_id, channel_type) == history:
        return
    temporary = None
    try:
        with tempfile.NamedTemporaryFile(mode='w', encoding='utf-8', dir=os.path.dirname(file_path),
                                         suffix='.tmp', delete=False) as f:
            temporary = f.name
            json.dump(history, f, ensure_ascii=False, indent=2)
        os.replace(temporary, file_path)
        temporary = None
        _history_changed(channel_type)
    except IOError as e:
        log_prefix = '[MyCinema]' if channel_type == 'cinema' else '[MyTV]'
        xbmc.log(f'{log_prefix} Error saving channel history {channel_id}: {e}', xbmc.LOGERROR)
    finally:
        if temporary:
            os.remove(temporary)


def update_series_progress(channel_id, series_id, season, episode, channel_type='tv', manual=False):
    """
    Aktualizuje progress seriálu v kanálu (pouze pro MyTV).
    
    Args:
        channel_id: ID kanálu
        series_id: TMDb ID seriálu (bude převedeno na string)
        season: Číslo sezóny
        episode: Číslo epizody
        channel_type: 'tv' pro MyTV (default)
        manual: ruční úprava postupu (ve společném režimu se zapíše i do knihovny;
                přehrávání tam zapisuje tracker služby)
    """
    if manual:
        shared = _shared(channel_type)
        if shared and not shared.set_pointer(series_id, season, episode):
            xbmc.log(f'[MyTV] Shared progress of series {series_id} not set: no episode list', xbmc.LOGWARNING)
    history = load_channel_history(channel_id, channel_type)
    history[str(series_id)] = {
        'season': int(season),
        'episode': int(episode)
    }
    save_channel_history(channel_id, history, channel_type)
    xbmc.log(f'[MyTV] Updated progress: channel={channel_id}, series={series_id}, S{season:02d}E{episode:02d}', xbmc.LOGINFO)


def mark_movie_watched(channel_id, movie_id, watched=True):
    """
    Označí film jako zhlédnutý v MyCinema kanálu.
    
    Args:
        channel_id: ID kanálu/kina
        movie_id: TMDb ID filmu
        watched: True pokud zhlédnuto
    """
    history = load_channel_history(channel_id, 'cinema')
    history[str(movie_id)] = {'watched': watched}
    save_channel_history(channel_id, history, 'cinema')
    xbmc.log(f'[MyCinema] Marked movie {movie_id} as watched in channel {channel_id}', xbmc.LOGINFO)


def is_movie_watched(channel_id, movie_id):
    """
    Zjistí, zda byl film zhlédnut v daném MyCinema kanálu.
    
    Args:
        channel_id: ID kanálu/kina
        movie_id: TMDb ID filmu
    
    Returns:
        bool: True pokud byl film zhlédnut
    """
    shared = _shared('cinema')
    if shared:
        return shared.movie_watched(movie_id)
    history = load_channel_history(channel_id, 'cinema')
    movie_data = history.get(str(movie_id), {})
    return movie_data.get('watched', False)


def get_series_progress(channel_id, series_id, channel_type='tv'):
    """
    Vrátí aktuální progress seriálu v kanálu.
    
    Args:
        channel_id: ID kanálu
        series_id: TMDb ID seriálu
        channel_type: 'tv' pro MyTV (default)
    
    Returns:
        tuple: (season, episode) nebo (1, 0) pokud neexistuje
    """
    shared = _shared(channel_type)
    if shared:
        return shared.pointer(series_id)
    history = load_channel_history(channel_id, channel_type)
    progress = history.get(str(series_id), {})
    return (
        progress.get('season', 1),
        progress.get('episode', 0)
    )


def set_resume_point(channel_id, series_id, season, episode, position, total):
    """
    Ulozi resume pozici rozkoukane epizody.
    
    Args:
        channel_id: ID kanalu
        series_id: TMDb ID serialu
        season: Sezona rozkoukane epizody
        episode: Cislo rozkoukane epizody
        position: Aktualni pozice v sekundach
        total: Celkova delka epizody v sekundach
    """
    history = load_channel_history(channel_id)
    sid = str(series_id)
    if sid not in history:
        history[sid] = {'season': 1, 'episode': 0}
    history[sid]['resume_position'] = round(float(position), 1)
    history[sid]['resume_total'] = round(float(total), 1)
    history[sid]['resume_s'] = int(season)
    history[sid]['resume_e'] = int(episode)
    save_channel_history(channel_id, history)
    # DEBUG
    xbmc.log(f"[DEBUG] ChannelHistory.set_resume_point: ch={channel_id} tmdb={series_id} S{season}E{episode} pos={position} total={total}", xbmc.LOGINFO)


def get_resume_point(channel_id, series_id):
    """
    Vrati resume data rozkoukane epizody.
    
    Args:
        channel_id: ID kanalu
        series_id: TMDb ID serialu
    
    Returns:
        dict s klici 'season', 'episode', 'position', 'total' nebo None
    """
    shared = _shared()
    if shared:
        return shared.resume(series_id)
    history = load_channel_history(channel_id)
    data = history.get(str(series_id), {})
    if 'resume_position' not in data:
        return None
    return {
        'season': data.get('resume_s', 1),
        'episode': data.get('resume_e', 1),
        'position': data.get('resume_position', 0),
        'total': data.get('resume_total', 0),
    }


def get_movie_resume_point(channel_id, movie_id):
    """
    Vrati resume data rozkoukaneho filmu v MyCinema: ve spolecnem rezimu z knihovny,
    jinak ze souboru kanalu (jako get_resume_point).
    """
    shared = _shared('cinema')
    if shared:
        return shared.movie_resume(movie_id)
    data = load_channel_history(channel_id).get(str(movie_id), {})
    if 'resume_position' not in data:
        return None
    return {'season': data.get('resume_s', 1), 'episode': data.get('resume_e', 1),
            'position': data.get('resume_position', 0), 'total': data.get('resume_total', 0)}


def clear_resume_point(channel_id, series_id):
    """
    Smaze resume pozici (epizoda shlednuta).
    
    Args:
        channel_id: ID kanalu
        series_id: TMDb ID serialu
    """
    history = load_channel_history(channel_id)
    sid = str(series_id)
    if sid in history:
        for key in ('resume_position', 'resume_total', 'resume_s', 'resume_e'):
            history[sid].pop(key, None)
        save_channel_history(channel_id, history)


def delete_channel_history(channel_id, channel_type='tv'):
    """
    Smaže historii kanálu (volat při mazání kanálu).
    
    Args:
        channel_id: ID kanálu
        channel_type: 'tv' pro MyTV, 'cinema' pro MyCinema
    """
    file_path = _get_history_file(channel_id, channel_type)
    log_prefix = '[MyCinema]' if channel_type == 'cinema' else '[MyTV]'
    if os.path.exists(file_path):
        try:
            history = load_channel_history(channel_id, channel_type)
            os.remove(file_path)
            if history:
                _history_changed(channel_type)
            xbmc.log(f'{log_prefix} Deleted channel history: {channel_id}', xbmc.LOGINFO)
            return True
        except OSError as e:
            xbmc.log(f'{log_prefix} Error deleting channel history {channel_id}: {e}', xbmc.LOGERROR)
    return False
