import xbmc
import xbmcgui
import xbmcplugin
import xbmcaddon
import xbmcvfs
import urllib.parse
import sys
import os

from endpoints import YOUTUBE_GENRES_DIR
from tools import debug_log
from analytics import track, track_error, track_feature, flush_session
from cache import save_youtube_cache, load_youtube_cache, clear_cache_files
from jet_parser import (parse_m3u8, parse_xmltv, normalize_id, get_url_settings, 
                     get_active_guide, set_active_guide)
from state_managers import FavoritesManager, LastWatchedManager
from channel_views import (
    add_context_menu_items,
    show_channel_listings as _show_channel_listings,
    show_favorites as _show_favorites,
    show_favorites_epg as _show_favorites_epg,
    test_directory as _test_directory,
    search_channels_and_programs as _search_channels_and_programs,
    show_main_menu as _show_main_menu,
    show_group as _show_group,
    show_channel as _show_channel,
    show_last_watched as _show_last_watched,
)
from sports_guide import parse_sports_json, show_sports_guide as _show_sports_guide

xbmc = xbmc
xbmcgui = xbmcgui
xbmcplugin = xbmcplugin

ADDON = xbmcaddon.Addon()
ADDONNAME = ADDON.getAddonInfo('name')
ADDONID = ADDON.getAddonInfo('id')
ICON = ADDON.getAddonInfo('icon')

_dialog_lock = False
_dialog_locked_by = None

def is_dialog_locked():
    return _dialog_lock

def acquire_dialog_lock(owner):
    global _dialog_lock, _dialog_locked_by
    if _dialog_lock:
        return False
    _dialog_lock = True
    _dialog_locked_by = owner
    return True

def release_dialog_lock(owner):
    global _dialog_lock, _dialog_locked_by
    if _dialog_locked_by == owner:
        _dialog_lock = False
        _dialog_locked_by = None

try:
    HANDLE = int(sys.argv[1])
except (IndexError, ValueError):
    HANDLE = 0
if HANDLE < 0:
    HANDLE = 0
BASE_URL = sys.argv[0]

active_guide = get_active_guide()
M3U8_PATH, XMLTV_PATH, XMLTV_EXTRA = get_url_settings(active_guide)

favorites_manager = FavoritesManager()
last_watched_manager = LastWatchedManager()

def show_sports_guide(progress_cb=None):
    return _show_sports_guide(acquire_dialog_lock, release_dialog_lock, ADDON, progress_cb=progress_cb)

def show_channel_listings():
    return _show_channel_listings(HANDLE, BASE_URL, ADDON, parse_m3u8, M3U8_PATH)


def show_favorites(handle=None):
    return _show_favorites(
        handle,
        BASE_URL,
        parse_m3u8,
        M3U8_PATH,
        favorites_manager,
        show_favorites_epg,
    )


def show_favorites_epg():
    return _show_favorites_epg(ADDON, parse_m3u8, parse_xmltv, M3U8_PATH, XMLTV_PATH, favorites_manager)


def test_directory(handle):
    return _test_directory(handle, BASE_URL)


def search_channels_and_programs(handle):
    return _search_channels_and_programs(
        handle,
        BASE_URL,
        parse_m3u8,
        parse_xmltv,
        M3U8_PATH,
        XMLTV_PATH,
        favorites_manager,
        acquire_dialog_lock,
        release_dialog_lock,
    )


def show_main_menu():
    return _show_main_menu(HANDLE, BASE_URL, ADDON, parse_m3u8, M3U8_PATH, get_active_guide, last_watched_manager)


def show_group(group_id):
    return _show_group(HANDLE, BASE_URL, parse_m3u8, M3U8_PATH, favorites_manager, group_id)


def show_channel(channel_id):
    return _show_channel(
        HANDLE,
        ADDON,
        parse_sports_json,
        parse_m3u8,
        parse_xmltv,
        M3U8_PATH,
        XMLTV_PATH,
        normalize_id,
        channel_id,
    )


def show_last_watched(handle=None):
    return _show_last_watched(handle, BASE_URL, last_watched_manager)

def switch_guide():
    try:
        current_guide = get_active_guide()
        new_guide = 2 if current_guide == 1 else 1
        m3u8_url, xmltv_url, extra_sources = get_url_settings(new_guide)
        if not m3u8_url or not xmltv_url:
            xbmcgui.Dialog().ok("Error", f"Guide {new_guide} is not configured. Please set up the URLs in settings first.")
            return
        
        clear_cache_files(new_guide)
        set_active_guide(new_guide)
        global M3U8_PATH, XMLTV_PATH, XMLTV_EXTRA
        M3U8_PATH, XMLTV_PATH, XMLTV_EXTRA = m3u8_url, xmltv_url, extra_sources
        
        xbmc.executebuiltin('Container.Refresh')
        xbmcgui.Dialog().notification('TV Guide', f'Switched to Guide {new_guide}', xbmcgui.NOTIFICATION_INFO, 2000)
        
    except Exception as e:
        xbmcgui.Dialog().ok("Error", f"Failed to switch guide: {str(e)}")

def play_channel(channel_id):
    try:
        channels = parse_m3u8(M3U8_PATH)
        channel = next((c for c in channels if c['tvg_id'] == channel_id), None)
        
        if not channel:
            cached_channels, cached_programs, cache_time = load_youtube_cache()
            youtube_channel = next((c for c in cached_channels if c['tvg_id'] == channel_id), None)
            youtube_programs = [p for p in cached_programs if p['channel'] == channel_id]
            if youtube_channel and youtube_programs:
                try:
                    from youtube_guide import cancel_youtube_playback, play_youtube_programs
                    track(event="play", channel_name=youtube_channel.get("name", ""), channel_id=youtube_channel.get("tvg_id", ""), url="", stream_type="youtube", source="cached")
                    debug_log("DEBUG: Cancelling any existing YouTube playback before starting new one", xbmc.LOGINFO)
                    cancel_youtube_playback()
                    play_youtube_programs(youtube_programs, is_new_channel=True)
                    return
                except Exception as e:
                    debug_log(f"DEBUG: Error in play_youtube_programs: {str(e)}", xbmc.LOGERROR)
                    xbmcgui.Dialog().ok("Playback Error", f"Failed to start YouTube playback: {str(e)}")
                    return
            from youtube_guide import fetch_links, fetch_json_content, youtube_json_to_epggrid
            import urllib.parse

            json_dir = YOUTUBE_GENRES_DIR
            youtube_channel = None
            youtube_programs = []
            
            try:
                xbmc.log(f"DEBUG: Searching for channel '{channel_id}' in remote JSON files", xbmc.LOGINFO)
                dirs, _ = fetch_links(json_dir)
                xbmc.log(f"DEBUG: Found {len(dirs)} genre directories", xbmc.LOGINFO)
                
                for href, genre_name in dirs:
                    if youtube_channel:
                        break
                    
                    xbmc.log(f"DEBUG: Checking genre: {genre_name}", xbmc.LOGINFO)
                    genre_url = urllib.parse.urljoin(json_dir, href + '/')
                    _, file_links = fetch_links(genre_url)
                    
                    for fhref, fname in file_links:
                        json_url = urllib.parse.urljoin(genre_url, fhref)
                        json_data = fetch_json_content(json_url)
                        
                        if json_data:
                            try:
                                channel_name = fname.replace('.json', '') if fname.endswith('.json') else fname
                                ch, pr = youtube_json_to_epggrid(json_data, channel_name)
                                
                                if ch and ch[0]['tvg_id'] == channel_id:
                                    xbmc.log(f"DEBUG: Found matching channel: {channel_id} in {fname}", xbmc.LOGINFO)
                                    youtube_channel = ch[0]
                                    youtube_programs = pr
                                    break
                                else:
                                    if ch:
                                        xbmc.log(f"DEBUG: Channel ID mismatch in {fname}. Looking for: {channel_id}, found: {ch[0].get('tvg_id', 'No ID')}", xbmc.LOGINFO)
                                        
                            except Exception as e:
                                xbmc.log(f"DEBUG: Failed to parse data from {json_url}: {str(e)}", xbmc.LOGERROR)
                        else:
                            xbmc.log(f"DEBUG: Skipped {json_url} (fetch failed)", xbmc.LOGWARNING)
                            
            except Exception as e:
                xbmc.log(f"Error fetching remote JSON files: {str(e)}", xbmc.LOGERROR)
            
            if youtube_channel:
                try:
                    from youtube_guide import cancel_youtube_playback, play_youtube_programs
                    debug_log("DEBUG: Cancelling any existing YouTube playback before starting new one", xbmc.LOGINFO)
                    cancel_youtube_playback()
                    xbmc.sleep(2000)
                    
                    try:
                        player = xbmc.Player()
                        if player.isPlaying():
                            debug_log("DEBUG: Force stopping player before new YouTube playlist", xbmc.LOGINFO)
                            player.stop()
                            xbmc.sleep(1000)
                    except:
                        pass
                    
                    track(event="play", channel_name=youtube_channel.get("name", ""), channel_id=youtube_channel.get("tvg_id", ""), url="", stream_type="youtube", source="remote")
                    debug_log(f"DEBUG: About to call play_youtube_programs with {len(youtube_programs)} programs", xbmc.LOGINFO)
                    play_youtube_programs(youtube_programs)
                    return
                except Exception as e:
                    debug_log(f"DEBUG: Error in play_youtube_programs: {str(e)}", xbmc.LOGERROR)
                    xbmcgui.Dialog().ok("Playback Error", f"Failed to start YouTube playback: {str(e)}")
                    return
            else:
                xbmcgui.Dialog().ok('Error', 'Channel not found')
                return
            
        channel_data = {
            'name': channel.get('name', 'Unknown'),
            'tvg_id': channel.get('tvg_id', ''),
            'url': channel.get('url', ''),
            'logo': channel.get('logo', ''),
            'group': channel.get('group', '')
        }
        try:
            last_watched_manager.add_last_watched(channel_data)
        except Exception as e:
            xbmcgui.Dialog().notification('Last Watched Error', f'Failed to save channel: {str(e)}', xbmcgui.NOTIFICATION_ERROR, 3000)
        
        url = channel.get('url', '')
        name = channel.get('name', '')
        
        if not url:
            xbmcgui.Dialog().ok('Error', 'No valid URL found for channel')
            return
        
        if '|' in url:
            streams = [s.strip() for s in url.split('|') if s.strip()]
            stream_names = []
            for stream in streams:
                if '(' in stream and ')' in stream:
                    stream_name = stream[stream.rindex('(')+1:stream.rindex(')')]
                    stream_names.append(stream_name)
                else:
                    stream_names.append(f"Stream {len(stream_names)+1}")
            
            dialog = xbmcgui.Dialog()
            choice = dialog.select('Choose Stream', stream_names)
            
            if choice >= 0:
                url = streams[choice].strip()
                if '(' in url:
                    url = url[:url.rindex('(')].strip()
            else:
                return
        else:
            resolved = False

        
        list_item = xbmcgui.ListItem(name)
        list_item.setInfo('video', {'title': name})
        list_item.setArt({'icon': channel.get('logo', '')})
        
        track(event="play", channel_name=name, channel_id=channel.get("tvg_id", ""), url=url, group=channel.get("group", ""), stream_type="direct")
        try:
            from youtube_guide import cancel_youtube_playback
            cancel_youtube_playback()
        except ImportError:
            pass

        player = xbmc.Player()
        player.play(item=url, listitem=list_item)
        
    except Exception as e:
        track_error(error_msg=str(e), channel_name=channel_id, source="play_channel")
        xbmcgui.Dialog().ok("Error", f"Failed to play channel: {str(e)}")

def show_sports_grid(sport):
    try:
        xbmc.executebuiltin('Dialog.Close(all)')
        xbmc.sleep(200)
        from sportsgrid import SportsGrid
        addon_path = ADDON.getAddonInfo('path')
        skin_xml = os.path.join(addon_path, 'resources', 'skins', 'default', '720p', 'sports.guide.xml')
        if not os.path.exists(skin_xml):
            raise Exception(f"Sports grid skin XML not found at {skin_xml}")
        
        xml_file = 'sports.guide.xml'
        window = SportsGrid(xml_file, addon_path, sport=sport)
        window.doModal()
        del window
        
    except Exception as e:
        xbmcgui.Dialog().ok("Error", f"Failed to load sports grid: {str(e)}")

def show_youtube_guide():
    from youtube_guide import fetch_links, fetch_json_content, youtube_json_to_epggrid
    from epggrid import EPGGrid
    import urllib.parse
    import xbmcaddon

    genre_map = {
        'Alternative Dance': 'youtube_genre_alternative_dance',
        'Alternative Metal': 'youtube_genre_alternative_metal',
        'Alternative Pop_Rock': 'youtube_genre_alternative_pop_rock',
        'Alternative Rap': 'youtube_genre_alternative_rap',
        'Alternative_Indie Rock': 'youtube_genre_alternative_indie_rock',
        'American Punk': 'youtube_genre_american_punk',
        'Arena Rock': 'youtube_genre_arena_rock',
        'College Rock': 'youtube_genre_college_rock',
        'Contemporary Pop_Rock': 'youtube_genre_contemporary_pop_rock',
        'Contemporary Rap': 'youtube_genre_contemporary_rap',
        'Contemporary Reggae': 'youtube_genre_contemporary_reggae',
        'Darkwave': 'youtube_genre_darkwave',
        'Death Metal': 'youtube_genre_death_metal',
        'EDM': 'youtube_genre_edm',
        'Electro-Industrial': 'youtube_genre_electro_industrial',
        'Electro-Techno': 'youtube_genre_electro_techno',
        'Electronica': 'youtube_genre_electronica',
        'Emo': 'youtube_genre_emo',
        'Funk': 'youtube_genre_funk',
        'Goth Metal': 'youtube_genre_goth_metal',
        'Goth Rock': 'youtube_genre_goth_rock',
        'Hair Metal': 'youtube_genre_hair_metal',
        'Hard Rock': 'youtube_genre_hard_rock',
        'Hardcore Rap': 'youtube_genre_hardcore_rap',
        'Heavy Metal': 'youtube_genre_heavy_metal',
        'Industrial': 'youtube_genre_industrial',
        'Industrial Dance': 'youtube_genre_industrial_dance',
        'Industrial Metal': 'youtube_genre_industrial_metal',
        'New Wave': 'youtube_genre_new_wave',
        'Nü Metal': 'youtube_genre_nu_metal',
        'Old-School Rap': 'youtube_genre_old_school_rap',
        'Punk': 'youtube_genre_punk',
        'Rap': 'youtube_genre_rap',
        'Rap-Rock': 'youtube_genre_rap_rock',
        'Ska': 'youtube_genre_ska',
        'Ska-Punk': 'youtube_genre_ska_punk',
        'Skatepunk': 'youtube_genre_skatepunk',
    }
    
    selected_genres_list = [genre for genre, setting_id in genre_map.items() if ADDON.getSetting(setting_id) == 'true']
    
    debug_log(f"DEBUG: Selected YouTube genres: {selected_genres_list if selected_genres_list else 'None (all disabled)'}", xbmc.LOGINFO)

    cached_channels, cached_programs, cache_time = load_youtube_cache()
    if cached_channels and cached_programs:
        debug_log(f"DEBUG: Using cached YouTube data, channels: {len(cached_channels)}, programs: {len(cached_programs)}", xbmc.LOGINFO)
        channels, programs = cached_channels, cached_programs
    else:
        debug_log("DEBUG: No valid cache found, fetching fresh YouTube data", xbmc.LOGINFO)
        json_dir = YOUTUBE_GENRES_DIR
        debug_log(f"DEBUG: Using json_dir for caching: {json_dir}", xbmc.LOGINFO)
        channels = []
        programs = []
        
        try:
            dirs, _ = fetch_links(json_dir)
            debug_log(f"DEBUG: Found {len(dirs)} genre directories for YouTube guide", xbmc.LOGINFO)
            
            for href, genre_name in dirs:
                genre_name_clean = genre_name.rstrip('/')
                if selected_genres_list and genre_name_clean not in selected_genres_list:
                    debug_log(f"DEBUG: Skipping genre '{genre_name}' (not in selected genres)", xbmc.LOGINFO)
                    continue
                debug_log(f"DEBUG: Processing genre: {genre_name}", xbmc.LOGINFO)
                genre_url = urllib.parse.urljoin(json_dir, href + '/')
                _, file_links = fetch_links(genre_url)
                
                for fhref, fname in file_links:
                    json_url = urllib.parse.urljoin(genre_url, fhref)
                    json_data = fetch_json_content(json_url)
                    
                    if json_data:
                        try:
                            channel_name = fname.replace('.json', '') if fname.endswith('.json') else fname
                            ch, pr = youtube_json_to_epggrid(json_data, channel_name)
                            channels.extend(ch)
                            programs.extend(pr)
                            debug_log(f"DEBUG: Added channel {ch[0]['name'] if ch else 'Unknown'} with {len(pr)} programs from {fname}", xbmc.LOGINFO)
                        except Exception as e:
                            debug_log(f"DEBUG: Failed to parse data from {json_url}: {str(e)}", xbmc.LOGERROR)
                    else:
                        debug_log(f"DEBUG: Skipped {json_url} (fetch failed)", xbmc.LOGWARNING)
                        
            if channels and programs:
                save_youtube_cache(channels, programs)
                debug_log(f"DEBUG: Saved YouTube cache with {len(channels)} channels and {len(programs)} programs", xbmc.LOGINFO)
                         
        except Exception as e:
            debug_log(f"ERROR: Failed to fetch YouTube guide data: {str(e)}", xbmc.LOGERROR)
            xbmcgui.Dialog().ok("Error", f"Failed to load YouTube guide: {str(e)}")
            return
    
    debug_log(f"DEBUG: Total YouTube channels: {len(channels)}, Total programs: {len(programs)}", xbmc.LOGINFO)
    for i, channel in enumerate(channels):
        channel_programs = [p for p in programs if p['channel'] == channel['tvg_id']]
        debug_log(f"DEBUG: Channel {i}: {channel['name']} ({channel['tvg_id']}) has {len(channel_programs)} programs", xbmc.LOGINFO)
    
    addon_path = xbmcaddon.Addon().getAddonInfo('path')
    win = EPGGrid('tuepg.guide.experimental.xml', addon_path, channels=channels, programs=programs)
    win.doModal()


def main():
    addon_path = ADDON.getAddonInfo('path')

    params = dict(urllib.parse.parse_qsl(sys.argv[2][1:]))
    action = params.get('action', '')
    try:
        handle = int(params.get('handle', sys.argv[1]))
    except (IndexError, ValueError):
        handle = 0
    if handle < 0:
        handle = 0

    if not action or action in ["open_guide", "show_main", "show_ten_buttons"]:
        track_feature(feature="home", action="open")
        xbmc.executebuiltin('Dialog.Close(all)')
        xbmc.sleep(200)
        from changelog_window import check_and_show_changelog
        check_and_show_changelog(addon_path)

    if action == 'show_youtube_guide':
        track_feature(feature="youtube", action="open")
        show_youtube_guide()
    elif action == 'test_directory':
        test_directory(handle)
    elif action == 'show_last_watched':
        show_last_watched(handle)
    if action == 'live_score_alerts':
        import livescore_alerts
        livescore_alerts.main()

    elif action == 'search':
        track_feature(feature="search", action="open")
        search_channels_and_programs(handle)
    elif action == 'show_favorites':
        track_feature(feature="favorites", action="open")
        show_favorites(handle)
    elif action == 'show_favorites_epg':
        track_feature(feature="favorites_epg", action="open")
        show_favorites_epg()
    elif action == 'remove_favorite':
        from favorites import favorites_manager
        channel_id = params.get('id')
        if channel_id and favorites_manager.remove_favorite(channel_id):
            xbmcgui.Dialog().notification('TV Guide', 'Channel removed from favorites')
            xbmc.executebuiltin('Container.Refresh')
    elif action == 'add_favorite':
        from favorites import favorites_manager
        channel_id = params.get('id')
        if channel_id and favorites_manager.add_favorite(channel_id):
            xbmcgui.Dialog().notification('TV Guide', 'Channel added to favorites')
    elif action == 'sports_grid':
        track_feature(feature="sports_grid", action="open", sport=params.get('sport', ''))
        show_sports_grid(params.get('sport'))
    elif action == 'team_info':
        from sportsgrid import TeamInfoWindow
        TeamInfoWindow.show_team_info(
            params.get('name', ''),
            params.get('logo', ''),
            params.get('record', '')
        )
    elif action == 'test_play':
        item = xbmcgui.ListItem("Test Playback")
        xbmcplugin.setResolvedUrl(handle, True, item)
    elif action == 'play_channel':
        play_channel(params.get('id'))
    elif action == 'settings':
        ADDON.openSettings()
    elif action == 'show_channel':
        show_channel(params['id'])
    elif action == 'show_group':
        show_group(params.get('group', ''))
    elif action == 'switch_guide':
        switch_guide()
    elif action == 'show_sports':
        track_feature(feature="sports_guide", action="open")
        show_sports_guide()
    elif action == 'show_ten_buttons':
        from tenbuttons import show_ten_buttons
        show_ten_buttons()
    elif action == 'refresh_tools':
        # Close Tools dialog and return to main menu so XML is re-read next time Tools opens
        xbmc.executebuiltin('Dialog.Close(all)')
        xbmc.sleep(300)
        # Reopen the main ten_buttons window so user can navigate back into Tools with fresh XML
        from tenbuttons import show_ten_buttons
        show_ten_buttons()
        return
    elif action == 'clear_last_watched':
        last_watched_manager.clear_history()
        xbmc.executebuiltin('Container.Refresh')
    elif action == 'add_favorite':
        channel_id = params.get('id')
        channels = parse_m3u8(M3U8_PATH)
        channel = next((c for c in channels if c['tvg_id'] == channel_id), None)
        if channel:
            if favorites_manager.add_favorite(channel):
                xbmcgui.Dialog().notification('Favorites', f'Added {channel["name"]} to favorites', xbmcgui.NOTIFICATION_INFO, 2000)
            else:
                xbmcgui.Dialog().notification('Favorites', 'Channel already in favorites', xbmcgui.NOTIFICATION_INFO, 2000)
    elif action == 'remove_favorite':
        channel_id = params.get('id')
        favorites_manager.remove_favorite(channel_id)
        xbmc.executebuiltin('Container.Refresh')
    elif action == 'epg_grid':
        track_feature(feature="epg", action="open")
        if not acquire_dialog_lock('epg_grid'):
            xbmcgui.Dialog().ok("Error", "Another process is running. Please wait.")
            return
            
        try:
            xbmc.executebuiltin('Dialog.Close(all)')
            xbmc.sleep(200)
            progress = xbmcgui.DialogProgress()
            progress.create('Loading TV Guide', 'Starting...')
            progress.update(0)

            def progress_cb(percent, message):
                try:
                    progress.update(max(0, min(100, int(percent))), message)
                except Exception:
                    pass

            from epggrid import EPGGrid
            channels = parse_m3u8(M3U8_PATH, progress_cb=progress_cb)
            programs = parse_xmltv(XMLTV_PATH, progress_cb=progress_cb)
            progress.update(94, 'Preparing guide window...')
            addon_path = ADDON.getAddonInfo('path')
            skin_base = os.path.join(addon_path, 'resources', 'skins', 'default')
            resolution = '720p'
            skin_xml = os.path.join(skin_base, resolution, 'tuepg.guide.experimental.xml')
            if not os.path.exists(skin_xml):
                raise Exception(f"EPG skin XML not found at {skin_xml}")

            xml_file = 'tuepg.guide.experimental.xml'
            xbmc.sleep(100)
            try:
                import shutil
                media_paths = {
                    'source': [
                        os.path.join(addon_path, 'resources', 'media'),
                        os.path.join(addon_path, 'resources', 'skins', 'default', 'media'),
                        os.path.join(addon_path, 'resources', 'skins', 'default', '720p', 'media')
                    ],
                    'dest': [
                        os.path.join(addon_path, 'resources', 'skins', 'default', '720p', 'media'),
                        os.path.join(addon_path, 'resources', 'media')
                    ]
                }
                for dest in media_paths['dest']:
                    os.makedirs(dest, exist_ok=True)
                    
                required_files = [
                    {'file': 'Background.png', 'desc': 'EPG background', 'required': True},
                    {'file': 'ButtonFocus.png', 'desc': 'Button highlight', 'required': True},
                    {'file': 'Panel.png', 'desc': 'Info panel', 'required': True},
                    {'file': 'white.png', 'desc': 'Scrollbar texture', 'required': True}
                ]
                
                for item in required_files:
                    found = False
                    for src in media_paths['source']:
                        src_file = os.path.join(src, item['file'])
                        if os.path.exists(src_file):
                            for dst in media_paths['dest']:
                                dst_file = os.path.join(dst, item['file'])
                                if not os.path.exists(dst_file):
                                    shutil.copy2(src_file, dst_file)
                            found = True
                            break
                            
                    if not found and item['required']:
                        raise Exception(f"Required media file missing: {item['file']} ({item['desc']})")
                window = EPGGrid(xml_file, addon_path, channels=channels, programs=programs)
                progress.update(100)
                progress.close()
                
                window.doModal()
                del window
                
            except Exception as e:
                progress.close()
                error_msg = f"EPG Error: {str(e)}"
                xbmcgui.Dialog().ok("EPG Error", error_msg)
                
        except Exception as e:
            xbmcgui.Dialog().ok("Error", f"Failed to load EPG: {str(e)}")
        finally:
            release_dialog_lock('epg_grid')
    elif action == 'show_listings':
        show_channel_listings()
    elif action == 'stop_youtube_playlist':
        try:
            from youtube_guide import cancel_youtube_playback
            cancel_youtube_playback()
            xbmcgui.Dialog().notification('YouTube', 'Playlist stopped', xbmcgui.NOTIFICATION_INFO, 2000)
        except Exception as e:
            xbmcgui.Dialog().notification('YouTube', f'Failed to stop playlist: {str(e)}', xbmcgui.NOTIFICATION_ERROR, 2000)
        return
    elif action == 'clear_cache':
        clear_cache_files(get_active_guide())
        for cache_file in [M3U8_PATH, XMLTV_PATH]:
            pass
        log_path = xbmcvfs.translatePath('special://logpath/kodi.log')
        if xbmcvfs.exists(log_path):
            xbmcvfs.delete(log_path)
        debug_log_path = xbmcvfs.translatePath('special://profile/addon_data/plugin.video.jet_guide/debug_log.txt')
        if xbmcvfs.exists(debug_log_path):
            xbmcvfs.delete(debug_log_path)
        debug_log_path_userdata = xbmcvfs.translatePath('special://userdata/addon_data/plugin.video.jet_guide/debug_log.txt')
        if xbmcvfs.exists(debug_log_path_userdata):
            xbmcvfs.delete(debug_log_path_userdata)
        xbmcgui.Dialog().notification('Cache', 'Cache cleared successfully', xbmcgui.NOTIFICATION_INFO, 2000)
        xbmc.executebuiltin('Container.Refresh')
    elif action == 'show_main':
        show_main_menu()
        return
    else:
        try:
            xbmc.executebuiltin('Dialog.Close(all)')
            xbmc.sleep(200)
            from tenbuttons import show_ten_buttons
            show_ten_buttons()
            if HANDLE > 0:
                xbmcplugin.endOfDirectory(HANDLE, succeeded=False)
        except Exception as e:
            xbmcgui.Dialog().ok("Error", f"Failed to start TV Guide: {str(e)}")

if __name__ == '__main__':
    main()
    flush_session()

if __name__ == "__main__":
    url = sys.argv[0]
    handle = int(sys.argv[1])
    import urllib.parse
    params = dict(urllib.parse.parse_qsl(sys.argv[2][1:])) if len(sys.argv) > 2 and sys.argv[2] else {}
    if not params or params.get("action") in ["open_guide", "show_main"]:
        li = xbmcgui.ListItem(label="Open TV Guide")
        xbmcplugin.addDirectoryItem(handle, url + "?action=open_guide", li, isFolder=True)
        xbmcplugin.endOfDirectory(handle)
    else:
        xbmcplugin.endOfDirectory(handle)
