import os
import urllib.parse
from datetime import datetime

import xbmc
import xbmcgui
import xbmcplugin
from analytics import track


def add_context_menu_items(list_item, channel, base_url, favorites_manager):
    context_menu = []
    guide_url = f"{base_url}?action=show_channel&id={urllib.parse.quote(channel['tvg_id'])}"
    context_menu.append(('Show Guide', f'Container.Update({guide_url})'))

    stop_youtube_action = f"{base_url}?action=stop_youtube_playlist"
    context_menu.append(('Stop YouTube Playlist', f'RunPlugin({stop_youtube_action})'))

    if favorites_manager.is_favorite(channel['tvg_id']):
        remove_action = f"{base_url}?action=remove_favorite&id={urllib.parse.quote(channel['tvg_id'])}"
        context_menu.append(('Remove from Favorites', f'RunPlugin({remove_action})'))
    else:
        add_action = f"{base_url}?action=add_favorite&id={urllib.parse.quote(channel['tvg_id'])}"
        context_menu.append(('Add to Favorites', f'RunPlugin({add_action})'))

    list_item.addContextMenuItems(context_menu)


def show_channel_listings(handle, base_url, addon, parse_m3u8, m3u8_path):
    try:
        if handle > 0:
            channels = parse_m3u8(m3u8_path)
            for channel in channels:
                name = channel['name']
                list_item = xbmcgui.ListItem(name)
                list_item.setArt({'icon': channel.get('logo', '')})
                context_menu = []
                guide_url = f"{base_url}?action=show_channel&id={urllib.parse.quote(channel['tvg_id'])}"
                context_menu.append(('Show Guide', f'Container.Update({guide_url})'))
                add_fav = f"{base_url}?action=add_favorite&id={urllib.parse.quote(channel['tvg_id'])}"
                context_menu.append(('Add to Favorites', f'RunPlugin({add_fav})'))
                list_item.addContextMenuItems(context_menu)
                url = f"{base_url}?action=play_channel&id={urllib.parse.quote(channel['tvg_id'])}"
                xbmcplugin.addDirectoryItem(handle, url, list_item, False)
            xbmcplugin.endOfDirectory(handle)
        else:
            from channellist import ChannelListWindow
            channels = parse_m3u8(m3u8_path)
            if not channels:
                xbmcgui.Dialog().ok('Channel List', 'No channels found')
                return
            addon_path = addon.getAddonInfo('path')
            window = ChannelListWindow('channel_list.xml', addon_path, channels=channels)
            window.doModal()
            del window

    except Exception as e:
        if handle > 0:
            xbmcplugin.endOfDirectory(handle, succeeded=False)
        xbmcgui.Dialog().ok("Error", f"Failed to load channel list: {str(e)}")


def show_favorites(
    handle,
    base_url,
    parse_m3u8,
    m3u8_path,
    favorites_manager,
    show_favorites_epg_fn,
):
    try:
        if handle is not None and handle > 0:
            channels = parse_m3u8(m3u8_path)
            favorite_channels = [c for c in channels if favorites_manager.is_favorite(c['tvg_id'])]

            if not favorite_channels:
                xbmcgui.Dialog().ok("TV Guide", "No favorite channels added yet")
                xbmcplugin.endOfDirectory(handle, succeeded=False)
                return
            guide = xbmcgui.ListItem("[COLOR yellow]► Open EPG View[/COLOR]")
            guide_url = f"{base_url}?action=show_favorites_epg"
            xbmcplugin.addDirectoryItem(handle, guide_url, guide, isFolder=True)
            for channel in favorite_channels:
                name = channel['name']
                item = xbmcgui.ListItem(name)
                item.setArt({'icon': channel.get('logo', '')})
                context_menu = []
                guide_url = f"{base_url}?action=show_channel&id={urllib.parse.quote(channel['tvg_id'])}"
                context_menu.append(('Show Guide', f'Container.Update({guide_url})'))
                remove_url = f"{base_url}?action=remove_favorite&id={urllib.parse.quote(channel['tvg_id'])}"
                context_menu.append(('Remove from Favorites', f'RunPlugin({remove_url})'))
                item.addContextMenuItems(context_menu)
                url = f"{base_url}?action=play_channel&id={urllib.parse.quote(channel['tvg_id'])}"
                xbmcplugin.addDirectoryItem(handle, url, item, isFolder=False)

            xbmcplugin.endOfDirectory(handle)
            return

        show_favorites_epg_fn()

    except Exception as e:
        if handle is not None and handle > 0:
            xbmcplugin.endOfDirectory(handle, succeeded=False)
        xbmcgui.Dialog().ok("Error", f"Failed to show favorites: {str(e)}")


def show_favorites_epg(addon, parse_m3u8, parse_xmltv, m3u8_path, xmltv_path, favorites_manager):
    progress = None
    try:
        from epggrid import EPGGrid
        xbmc.executebuiltin('Dialog.Close(all)')
        xbmc.sleep(200)

        progress = xbmcgui.DialogProgress()
        progress.create('Loading Favorites Guide', 'Starting...')
        progress.update(0)

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

        channels = parse_m3u8(m3u8_path, progress_cb=progress_cb)
        programs = parse_xmltv(xmltv_path, progress_cb=progress_cb)

        progress.update(93, 'Filtering favorites channels...')
        favorite_channels = [c for c in channels if favorites_manager.is_favorite(c['tvg_id'])]
        if not favorite_channels:
            progress.close()
            xbmcgui.Dialog().ok("TV Guide", "No favorite channels added yet")
            return

        favorite_channel_ids = [c['tvg_id'] for c in favorite_channels]
        favorite_programs = [p for p in programs if p['channel'] in favorite_channel_ids]

        progress.update(98, 'Opening favorites guide...')
        addon_path = addon.getAddonInfo('path')
        epg_window = EPGGrid(
            'tuepg.guide.experimental.xml',
            addon_path,
            channels=favorite_channels,
            programs=favorite_programs,
            is_favorites_view=True,
        )
        progress.update(100)
        progress.close()

        epg_window.doModal()
        del epg_window

    except Exception as e:
        if progress:
            try:
                progress.close()
            except Exception:
                pass
        xbmcgui.Dialog().ok("Error", f"Failed to show favorites: {str(e)}")


def test_directory(handle, base_url):
    test_item1 = xbmcgui.ListItem("[COLOR green]Simple Test Item[/COLOR]")
    xbmcplugin.addDirectoryItem(handle, "", test_item1, False)

    test_item2 = xbmcgui.ListItem("[COLOR blue]Test Item with URL[/COLOR]")
    test_url = f"{base_url}?action=test_play"
    xbmcplugin.addDirectoryItem(handle, test_url, test_item2, False)

    test_item3 = xbmcgui.ListItem("[COLOR yellow]Test Video Item[/COLOR]")
    info_tag = test_item3.getVideoInfoTag()
    info_tag.setTitle("Test Video")
    info_tag.setPlot("This is a test video item")
    test_url = f"{base_url}?action=test_play"
    xbmcplugin.addDirectoryItem(handle, test_url, test_item3, False)
    xbmcplugin.endOfDirectory(handle, succeeded=True, cacheToDisc=False)


def return_to_buttons():
    xbmc.executebuiltin('ActivateWindow(13002)')


def search_channels_and_programs(
    handle,
    base_url,
    parse_m3u8,
    parse_xmltv,
    m3u8_path,
    xmltv_path,
    favorites_manager,
    acquire_dialog_lock,
    release_dialog_lock,
):
    if not acquire_dialog_lock('search_channels'):
        xbmcgui.Dialog().ok("Error", "Another process is running. Please wait.")
        xbmcplugin.endOfDirectory(handle, succeeded=False)
        return

    progress = None
    try:
        keyboard = xbmc.Keyboard('', 'Search')
        keyboard.doModal()
        if not keyboard.isConfirmed():
            xbmcplugin.endOfDirectory(handle, succeeded=False)
            return_to_buttons()
            return

        search_term = keyboard.getText().lower().strip()
        if not search_term:
            xbmcplugin.endOfDirectory(handle, succeeded=False)
            return_to_buttons()
            return

        progress = xbmcgui.DialogProgress()
        progress.create('Searching', 'Loading data...')

        channels = parse_m3u8(m3u8_path)
        programs = parse_xmltv(xmltv_path)
        current_time = datetime.now().astimezone()

        progress.update(25, 'Indexing programs...')
        channel_programs = {}
        for program in programs:
            if program['stop'] >= current_time:
                channel_id = program['channel']
                if channel_id not in channel_programs:
                    channel_programs[channel_id] = []
                channel_programs[channel_id].append(program)

        progress.update(50, 'Searching...')
        found_channels = []
        found_programs = []

        for channel in channels:
            if progress.iscanceled():
                xbmcplugin.endOfDirectory(handle, succeeded=False)
                return_to_buttons()
                return

            if search_term in channel['name'].lower():
                found_channels.append(channel)

            channel_id = channel['tvg_id']
            if channel_id in channel_programs:
                for program in channel_programs[channel_id]:
                    if search_term in program['title'].lower():
                        found_programs.append({'program': program, 'channel': channel})

        progress.update(75, 'Displaying results...')
        header = xbmcgui.ListItem(f'[COLOR gold]Search Results for "{search_term}"[/COLOR]')
        xbmcplugin.addDirectoryItem(handle, '', header, False)
        if found_channels:
            section = xbmcgui.ListItem(f'[COLOR yellow]Matching Channels ({len(found_channels)})[/COLOR]')
            xbmcplugin.addDirectoryItem(handle, '', section, False)
            for channel in found_channels:
                name = f"[COLOR yellow]► {channel['name']}[/COLOR]"
                item = xbmcgui.ListItem(name)
                item.setArt({'icon': channel['logo'], 'thumb': channel['logo']})
                add_context_menu_items(item, channel, base_url, favorites_manager)
                url = f"{base_url}?action=play_channel&id={urllib.parse.quote(channel['tvg_id'])}"
                xbmcplugin.addDirectoryItem(handle, url, item, False)

        if found_programs:
            if found_channels:
                separator = xbmcgui.ListItem('[COLOR blue]════════════════════[/COLOR]')
                xbmcplugin.addDirectoryItem(handle, '', separator, False)
            section = xbmcgui.ListItem(f'[COLOR lime]Matching Programs ({len(found_programs)})[/COLOR]')
            xbmcplugin.addDirectoryItem(handle, '', section, False)
            for item in found_programs:
                program = item['program']
                channel = item['channel']
                start_time = program['start'].strftime('%H:%M')
                name = f"    {start_time} - {program['title']} ({channel['name']})"
                list_item = xbmcgui.ListItem(name)
                list_item.setArt({'icon': channel['logo'], 'thumb': channel['logo']})
                list_item.getVideoInfoTag().setTitle(program['title'])
                list_item.getVideoInfoTag().setPlot(program.get('desc', ''))
                add_context_menu_items(list_item, channel, base_url, favorites_manager)
                url = f"{base_url}?action=play_channel&id={urllib.parse.quote(channel['tvg_id'])}"
                xbmcplugin.addDirectoryItem(handle, url, list_item, False)
        if not found_channels and not found_programs:
            msg = xbmcgui.ListItem('[COLOR red]No matches found[/COLOR]')
            xbmcplugin.addDirectoryItem(handle, '', msg, False)

        xbmcplugin.endOfDirectory(handle, succeeded=True)
    except Exception:
        xbmcgui.Dialog().notification('Search Error', 'Failed to complete search', xbmcgui.NOTIFICATION_ERROR)
        xbmcplugin.endOfDirectory(handle, succeeded=False)

    finally:
        if progress:
            try:
                progress.close()
            except Exception:
                pass
        release_dialog_lock('search_channels')


def show_main_menu(handle, base_url, addon, parse_m3u8, m3u8_path, get_active_guide, last_watched_manager):
    try:
        parse_m3u8(m3u8_path)
        search_item = xbmcgui.ListItem("[COLOR lime]Search Channels & Programs[/COLOR]")
        search_url = f"{base_url}?action=search"
        xbmcplugin.addDirectoryItem(handle, search_url, search_item, True)

        sports_header = xbmcgui.ListItem("[COLOR orange]===== Sports Grids =====[/COLOR]")
        xbmcplugin.addDirectoryItem(handle, "", sports_header, False)

        sports = [("MLB", "mlb"), ("NBA", "nba"), ("WNBA", "wnba"), ("NHL", "nhl"), ("NFL", "nfl")]

        for name, sport in sports:
            sports_item = xbmcgui.ListItem(f"[COLOR orange]{name} Grid View[/COLOR]")
            sports_url = f"{base_url}?action=sports_grid&sport={sport}"
            xbmcplugin.addDirectoryItem(handle, sports_url, sports_item, False)

        sports_separator = xbmcgui.ListItem("[COLOR orange]==================[/COLOR]")
        xbmcplugin.addDirectoryItem(handle, "", sports_separator, False)
        test_item = xbmcgui.ListItem("[COLOR red]Test Directory[/COLOR]")
        test_url = f"{base_url}?action=test_directory&handle={handle}"
        xbmcplugin.addDirectoryItem(handle, test_url, test_item, True)

        settings_item = xbmcgui.ListItem("[COLOR lime]Settings[/COLOR]")
        settings_url = f"{base_url}?action=settings"
        xbmcplugin.addDirectoryItem(handle, settings_url, settings_item, False)

        epg_item = xbmcgui.ListItem("[COLOR yellow]EPG Grid View[/COLOR]")
        epg_url = f"{base_url}?action=epg_grid"
        xbmcplugin.addDirectoryItem(handle, epg_url, epg_item, False)

        favorites_item = xbmcgui.ListItem("[COLOR gold]Favorite Channels[/COLOR]")
        favorites_url = f"{base_url}?action=show_favorites"
        xbmcplugin.addDirectoryItem(handle, favorites_url, favorites_item, True)

        if last_watched_manager.load_last_watched():
            last_watched_item = xbmcgui.ListItem("[COLOR skyblue]Last Watched Channels[/COLOR]")
            last_watched_url = f"{base_url}?action=show_last_watched"
            xbmcplugin.addDirectoryItem(handle, last_watched_url, last_watched_item, True)

            clear_item = xbmcgui.ListItem("[COLOR red]Clear Last Watched History[/COLOR]")
            clear_url = f"{base_url}?action=clear_last_watched"
            xbmcplugin.addDirectoryItem(handle, clear_url, clear_item, False)
        else:
            disabled_item = xbmcgui.ListItem("[COLOR gray]Last Watched Channels (None)[/COLOR]")
            xbmcplugin.addDirectoryItem(handle, "", disabled_item, False)

        sports_item = xbmcgui.ListItem("[COLOR orange]Sports Events[/COLOR]")
        sports_url = f"{base_url}?action=show_sports"
        xbmcplugin.addDirectoryItem(handle, sports_url, sports_item, False)

        ten_buttons_item = xbmcgui.ListItem("[COLOR cyan]Ten Buttons Interface[/COLOR]")
        ten_buttons_url = f"{base_url}?action=show_ten_buttons"
        xbmcplugin.addDirectoryItem(handle, ten_buttons_url, ten_buttons_item, False)

        channels_item = xbmcgui.ListItem("[COLOR yellow]All Channel Listings[/COLOR]")
        channels_url = f"{base_url}?action=show_listings"
        xbmcplugin.addDirectoryItem(handle, channels_url, channels_item, True)

        m3u8_url_2 = addon.getSetting('m3u8_url_2')
        if m3u8_url_2:
            active_guide = get_active_guide()
            guide_switch_item = xbmcgui.ListItem(f"[COLOR lime]Switch to Guide {1 if active_guide == 2 else 2}[/COLOR]")
            guide_switch_url = f"{base_url}?action=switch_guide"
            xbmcplugin.addDirectoryItem(handle, guide_switch_url, guide_switch_item, False)

        clear_cache_item = xbmcgui.ListItem("[COLOR red]Clear Cache[/COLOR]")
        clear_cache_url = f"{base_url}?action=clear_cache"
        xbmcplugin.addDirectoryItem(handle, clear_cache_url, clear_cache_item, False)
        xbmcplugin.endOfDirectory(handle)

    except Exception:
        xbmcplugin.endOfDirectory(handle, succeeded=False)


def show_group(handle, base_url, parse_m3u8, m3u8_path, favorites_manager, group_id):
    try:
        channels = parse_m3u8(m3u8_path)
        group_channels = [c for c in channels if c.get('group') == group_id]

        for channel in group_channels:
            name = channel['name']
            if favorites_manager.is_favorite(channel['tvg_id']):
                name = f"[COLOR gold]★[/COLOR] {name}"

            list_item = xbmcgui.ListItem(name)
            list_item.setArt({'icon': channel['logo']})

            if favorites_manager.is_favorite(channel['tvg_id']):
                remove_action = f"{base_url}?action=remove_favorite&id={urllib.parse.quote(channel['tvg_id'])}"
                list_item.addContextMenuItems([('Remove from Favorites', f'RunPlugin({remove_action})')])
            else:
                add_action = f"{base_url}?action=add_favorite&id={urllib.parse.quote(channel['tvg_id'])}"
                list_item.addContextMenuItems([('Add to addon Favorites', f'RunPlugin({add_action})')])

            url = f"{base_url}?action=show_channel&id={urllib.parse.quote(channel['tvg_id'])}"
            xbmcplugin.addDirectoryItem(handle, url, list_item, True)

        xbmcplugin.endOfDirectory(handle)

    except Exception:
        xbmcplugin.endOfDirectory(handle, succeeded=False)


def show_channel(handle, addon, parse_sports_json, parse_m3u8, parse_xmltv, m3u8_path, xmltv_path, normalize_id, channel_id):
    try:
        if channel_id.startswith('sports_'):
            channels, _ = parse_sports_json(addon.getSetting('sports_url'))
            channel = next((c for c in channels if c['tvg_id'] == channel_id), None)
            if not channel:
                raise ValueError(f"Sports event {channel_id} not found")

            if 'all_links' in channel and channel['all_links']:
                stream_names = channel.get('stream_names', [])
                dialog = xbmcgui.Dialog()
                choice = dialog.select('Choose Stream', stream_names)

                if choice >= 0:
                    url = channel['all_links'][choice]
                    if '(' in url:
                        url = url[:url.rindex('(')]
                    track(event="play", channel_name=channel['name'], channel_id=channel.get('tvg_id', ''), url=url, source="channel_views")
                    list_item = xbmcgui.ListItem(channel['name'])
                    list_item.setPath(url)
                    xbmc.Player().play(url, list_item)
            return

        channels = parse_m3u8(m3u8_path)
        programs = parse_xmltv(xmltv_path)
        channel = next((c for c in channels if c['tvg_id'] == channel_id), None)
        if not channel:
            raise ValueError(f"Channel {channel_id} not found")

        normalized_id = normalize_id(channel_id)
        now = datetime.now().astimezone()

        current_program = None
        upcoming_programs = []

        for program in programs:
            if normalize_id(program['channel']) != normalized_id:
                continue

            if program['start'] <= now <= program['stop']:
                current_program = program
            elif program['start'] > now:
                upcoming_programs.append(program)
                if len(upcoming_programs) >= 5:
                    break

        if current_program:
            time_str = f"{current_program['start'].strftime('%H:%M')} - {current_program['stop'].strftime('%H:%M')}"
            title = f"{time_str}: [COLOR yellow]{current_program['title']}[/COLOR] [COLOR lime](Now)[/COLOR]"
            list_item = xbmcgui.ListItem(title)
            xbmcplugin.addDirectoryItem(handle, channel['url'], list_item, False)

        today = now.date()
        for program in upcoming_programs:
            time_str = f"{program['start'].strftime('%H:%M')} - {program['stop'].strftime('%H:%M')}"
            if program['start'].date() > today:
                time_str = f"[Tomorrow] {time_str}"
            title = f"{time_str}: {program['title']}"
            list_item = xbmcgui.ListItem(title)
            xbmcplugin.addDirectoryItem(handle, channel['url'], list_item, False)

        xbmcplugin.endOfDirectory(handle)

    except Exception:
        xbmcplugin.endOfDirectory(handle, succeeded=False)


def show_last_watched(handle, base_url, last_watched_manager):
    try:
        if handle is not None and handle > 0:
            channels = last_watched_manager.load_last_watched()
            if not channels:
                xbmcgui.Dialog().ok("TV Guide", "No recently watched channels")
                xbmcplugin.endOfDirectory(handle, succeeded=False)
                return
            for channel in channels:
                name = channel.get('name', 'Unknown')
                item = xbmcgui.ListItem(name)
                item.setArt({'icon': channel.get('logo', '')})
                context_menu = []
                if channel.get('tvg_id'):
                    guide_url = f"{base_url}?action=show_channel&id={urllib.parse.quote(channel['tvg_id'])}"
                    context_menu.append(('Show Guide', f'Container.Update({guide_url})'))
                item.addContextMenuItems(context_menu)
                url = f"{base_url}?action=play_channel&id={urllib.parse.quote(channel['tvg_id'])}"
                xbmcplugin.addDirectoryItem(handle, url, item, isFolder=False)
            xbmcplugin.endOfDirectory(handle)
            return

    except Exception as e:
        if handle is not None and handle > 0:
            xbmcplugin.endOfDirectory(handle, succeeded=False)
        xbmcgui.Dialog().ok("Error", f"Failed to show last watched: {str(e)}")
