import xbmc
import xbmcgui
import xbmcvfs
import json
import os
import time
from datetime import datetime, timedelta, timezone

from tools import debug_log

ADDON = None

def _get_addon():
    global ADDON
    if ADDON is None:
        import xbmcaddon
        ADDON = xbmcaddon.Addon()
    return ADDON

def get_cache_path():
    addon = _get_addon()
    return xbmcvfs.translatePath(addon.getAddonInfo('profile'))

CACHE_PATH = None

def _ensure_cache_path():
    global CACHE_PATH
    if CACHE_PATH is None:
        CACHE_PATH = get_cache_path()
        if not xbmcvfs.exists(CACHE_PATH):
            xbmcvfs.mkdirs(CACHE_PATH)
    return CACHE_PATH

SPORTS_CACHE_DURATION = 6 * 60 * 60
YOUTUBE_CACHE_DURATION = 6 * 60 * 60

def get_sports_cache_file():
    p = _ensure_cache_path()
    return os.path.join(p, 'sports_cache.json')

def get_sports_cache_time_file():
    p = _ensure_cache_path()
    return os.path.join(p, 'sports_cache_time.txt')

def get_youtube_cache_file():
    p = _ensure_cache_path()
    return os.path.join(p, 'youtube_cache.json')

def get_youtube_cache_time_file():
    p = _ensure_cache_path()
    return os.path.join(p, 'youtube_cache_time.txt')

def datetime_handler(obj):
    if isinstance(obj, datetime):
        return obj.isoformat()
    raise TypeError(f"Object of type {type(obj)} is not JSON serializable")

def parse_datetime(datetime_str):
    try:
        return datetime.fromisoformat(datetime_str)
    except:
        return None

def save_cache(data, cache_file, time_file):
    try:
        with open(cache_file, 'w') as f:
            json.dump(data, f, default=datetime_handler)
        with open(time_file, 'w') as f:
            f.write(datetime.now().isoformat())
    except Exception as e:
        pass

def load_cache(cache_file, time_file):
    try:
        if xbmcvfs.exists(cache_file) and xbmcvfs.exists(time_file):
            with open(cache_file, 'r') as f:
                data = json.load(f)
                if isinstance(data, list):
                    for item in data:
                        if isinstance(item, dict):
                            if 'start' in item:
                                item['start'] = parse_datetime(item['start'])
                            if 'stop' in item:
                                item['stop'] = parse_datetime(item['stop'])
            with open(time_file, 'r') as f:
                cache_time = parse_datetime(f.read().strip())
            if cache_time and is_cache_valid(cache_time):
                return data, cache_time
    except Exception as e:
        pass
    return None, None

def is_cache_valid(cache_time):
    if not cache_time:
        return False
    return (datetime.now() - cache_time).total_seconds() < get_cache_duration()

def get_cache_duration():
    duration_map = {
        '6 hours': 6 * 3600,
        '12 hours': 12 * 3600,
        '1 day': 24 * 3600,
        '2 days': 48 * 3600,
        '3 days': 72 * 3600,
        '1 week': 7 * 24 * 3600,
    }
    addon = _get_addon()
    setting_value = addon.getSetting('cache_duration') or '6 hours'
    return duration_map.get(setting_value, 6 * 3600)

def save_sports_cache(channels, programs):
    cache_file = get_sports_cache_file()
    time_file = get_sports_cache_time_file()
    try:
        cache_data = {'channels': channels, 'programs': programs}
        with xbmcvfs.File(cache_file, 'w') as f:
            f.write(json.dumps(cache_data, default=datetime_handler, indent=2, ensure_ascii=False))
        with xbmcvfs.File(time_file, 'w') as f:
            f.write(datetime.now().isoformat())
    except Exception as e:
        pass

def load_sports_cache():
    cache_file = get_sports_cache_file()
    time_file = get_sports_cache_time_file()
    try:
        if xbmcvfs.exists(cache_file) and xbmcvfs.exists(time_file):
            with xbmcvfs.File(time_file, 'r') as f:
                cache_time = parse_datetime(f.read().strip())
            if cache_time and (datetime.now() - cache_time).total_seconds() < SPORTS_CACHE_DURATION:
                with xbmcvfs.File(cache_file, 'r') as f:
                    data = json.loads(f.read())
                for program in data.get('programs', []):
                    if 'start' in program:
                        program['start'] = parse_datetime(program['start'])
                    if 'stop' in program:
                        program['stop'] = parse_datetime(program['stop'])
                return data.get('channels', []), data.get('programs', []), cache_time
    except Exception as e:
        pass
    return [], [], None

def save_youtube_cache(channels, programs):
    cache_file = get_youtube_cache_file()
    time_file = get_youtube_cache_time_file()
    try:
        cache_data = {'channels': channels, 'programs': programs}
        with xbmcvfs.File(cache_file, 'w') as f:
            f.write(json.dumps(cache_data, default=datetime_handler, indent=2, ensure_ascii=False))
        with xbmcvfs.File(time_file, 'w') as f:
            f.write(datetime.now().isoformat())
        debug_log(f"Saved YouTube cache to {cache_file}", xbmc.LOGINFO)
    except Exception as e:
        debug_log(f"Failed to save YouTube cache: {str(e)}", xbmc.LOGERROR)

def load_youtube_cache():
    cache_file = get_youtube_cache_file()
    time_file = get_youtube_cache_time_file()
    try:
        if xbmcvfs.exists(cache_file) and xbmcvfs.exists(time_file):
            with xbmcvfs.File(time_file, 'r') as f:
                cache_time = parse_datetime(f.read().strip())
            if cache_time and (datetime.now() - cache_time).total_seconds() < YOUTUBE_CACHE_DURATION:
                with xbmcvfs.File(cache_file, 'r') as f:
                    data = json.loads(f.read())
                for program in data.get('programs', []):
                    if 'start' in program:
                        program['start'] = parse_datetime(program['start'])
                    if 'stop' in program:
                        program['stop'] = parse_datetime(program['stop'])
                debug_log(f"Loaded YouTube cache from {cache_file}", xbmc.LOGINFO)
                return data.get('channels', []), data.get('programs', []), cache_time
    except Exception as e:
        debug_log(f"Failed to load YouTube cache: {str(e)}", xbmc.LOGERROR)
    return [], [], None

def _offset_cache_suffix():
    addon = _get_addon()
    suffix_offsets_setting = (addon.getSetting('epg_suffix_offsets') or '').strip()
    if not suffix_offsets_setting:
        return ""
    import hashlib
    hash_val = hashlib.md5(suffix_offsets_setting.encode('utf-8')).hexdigest()[:8]
    return f"_offset_{hash_val}"

def get_cache_files(guide_number=1):
    p = _ensure_cache_path()
    suffix = f"_{guide_number}" if guide_number > 1 else ""
    offset_suffix = _offset_cache_suffix()
    return {
        'm3u8': os.path.join(p, f'm3u8_cache{suffix}.json'),
        'xmltv': os.path.join(p, f'xmltv_cache{suffix}{offset_suffix}.json'),
        'm3u8_time': os.path.join(p, f'm3u8_cache_time{suffix}.txt'),
        'xmltv_time': os.path.join(p, f'xmltv_cache_time{suffix}{offset_suffix}.txt'),
        'debug_log': os.path.join(p, 'debug_log.txt')
    }

def clear_cache_files(guide_number=None):
    try:
        if guide_number is None:
            import jet_parser as _p
            guide_number = _p.get_active_guide()
        cache_files = get_cache_files(guide_number)
        for cache_file in cache_files.values():
            if os.path.exists(cache_file):
                os.remove(cache_file)
        debug_log(f"Cache files cleared for guide {guide_number}", xbmc.LOGINFO)
    except Exception as e:
        debug_log(f"Failed to clear cache: {str(e)}", xbmc.LOGERROR)

def _safe_progress_update(progress_cb, percent, message):
    if not progress_cb:
        return
    try:
        progress_cb(int(percent), str(message))
    except Exception:
        pass
