import json
import os
import urllib.parse
from datetime import datetime, timedelta, timezone

import xbmc
import xbmcgui
import xbmcvfs

from cache import load_sports_cache, save_sports_cache, _safe_progress_update
from endpoints import SPORTS_URLS
from tools import debug_log


def parse_sports_data(data, sport_type):
    channels = []
    programs = []
    default_sports_icon = 'special://home/addons/plugin.video.jet_guide/resources/skins/default/720p/media/sports_icon.png'

    debug_log(f"DEBUG: Parsing sports data for {sport_type}, items: {len(data.get('items', []))}", xbmc.LOGINFO)
    for item in data.get('items', []):
        if item.get('type') != 'item':
            continue
        title = item.get('title', '').replace('[COLOR]', '').replace('[/COOR]', '')
        league = item.get('league', sport_type)
        links = item.get('link', [])
        fanart = item.get('fanart', '') or default_sports_icon
        thumbnail = item.get('thumbnail', '') or default_sports_icon
        guide_data = item.get('guidedata', [])

        if not guide_data:
            continue
        channel_id = f"sports_{sport_type}_{len(channels)}"
        stream_names = []
        for link in links:
            if '(' in link and ')' in link:
                name = link[link.rindex('(') + 1:link.rindex(')')]
                stream_names.append(name)
            else:
                stream_names.append(f"Stream {len(stream_names) + 1}")

        channel = {
            'name': title,
            'tvg_id': channel_id,
            'logo': fanart if fanart != default_sports_icon else thumbnail,
            'group': league.upper(),
            'url': links[0] if links else '',
            'all_links': links,
            'stream_names': stream_names,
        }
        channels.append(channel)
        for event in guide_data:
            start_time = datetime.fromtimestamp(event.get('starttime', 0), tz=timezone.utc)
            duration = event.get('duration', 7200)
            stop_time = start_time + timedelta(seconds=duration)
            program = {
                'channel': channel_id,
                'start': start_time,
                'stop': stop_time,
                'title': event.get('label', title).replace('[COLOR]', '').replace('[/COOR]', ''),
                'desc': f"Available on: {len(links)} sources",
                'category': [league.upper()],
                'icon': {'src': fanart},
            }
            programs.append(program)

    return channels, programs


def parse_sports_json(progress_cb=None, addon=None):
    # Backward-compat: callers may pass non-callable value by mistake
    if not callable(progress_cb):
        progress_cb = None

    try:
        if addon is None:
            import xbmcaddon
            addon = xbmcaddon.Addon()

        cached_channels, cached_programs, _ = load_sports_cache()
        if cached_channels and cached_programs:
            _safe_progress_update(progress_cb, 75, f"Using cached sports data ({len(cached_channels)} channels)")
            return cached_channels, cached_programs

        all_channels = []
        all_programs = []
        headers = {'User-Agent': 'Mozilla/5.0'}
        sports_urls = [
            ('ppv', 'include_ppv', 'ppv_url'), ('nba', 'include_nba', 'nba_url'), ('ufc', 'include_ufc', 'ufc_url'),
            ('boxing', 'include_boxing', 'boxing_url'), ('nfl', 'include_nfl', 'nfl_url'), ('mlb', 'include_mlb', 'mlb_url'),
            ('nhl', 'include_nhl', 'nhl_url'), ('basketball', 'include_basketball', 'basketball_url'),
            ('ice_hockey', 'include_ice_hockey', 'ice_hockey_url'), ('ncaaf', 'include_ncaaf', 'ncaaf_url'),
            ('ncaab', 'include_ncaab', 'ncaab_url'), ('ncaa_baseball', 'include_ncaa_baseball', 'ncaa_baseball_url'),
            ('wrestling', 'include_wrestling', 'wrestling_url'), ('soccer', 'include_soccer', 'soccer_url'),
            ('england_soccer', 'include_england_soccer', 'england_soccer_url'), ('mls', 'include_mls', 'mls_url'),
            ('athletics', 'include_athletics', 'athletics_url'), ('aussie_rules', 'include_aussie_rules', 'aussie_rules_url'),
            ('bowling', 'include_bowling', 'bowling_url'), ('cfl', 'include_cfl', 'cfl_url'), ('cricket', 'include_cricket', 'cricket_url'),
            ('cycling', 'include_cycling', 'cycling_url'), ('darts', 'include_darts', 'darts_url'), ('futsal', 'include_futsal', 'futsal_url'),
            ('gaa', 'include_gaa', 'gaa_url'), ('golf', 'include_golf', 'golf_url'), ('gymnastics', 'include_gymnastics', 'gymnastics_url'),
            ('handball', 'include_handball', 'handball_url'), ('horse_racing', 'include_horse_racing', 'horse_racing_url'),
            ('lacrosse', 'include_lacrosse', 'lacrosse_url'), ('motorsport', 'include_motorsport', 'motorsport_url'),
            ('rugby', 'include_rugby', 'rugby_url'), ('sailing_boating', 'include_sailing_boating', 'sailing_boating_url'),
            ('snooker', 'include_snooker', 'snooker_url'), ('squash', 'include_squash', 'squash_url'),
            ('tennis', 'include_tennis', 'tennis_url'), ('volleyball', 'include_volleyball', 'volleyball_url'),
            ('water_sports', 'include_water_sports', 'water_sports_url'), ('espn_plus', 'include_espn_plus', 'espn_plus_url'),
            ('events', 'include_events', 'events_url'),
        ]

        enabled_sources = []
        for sport_type, setting, url_setting in sports_urls:
            if addon.getSettingBool(setting):
                url = addon.getSetting(url_setting)
                if not url:
                    url = SPORTS_URLS.get(sport_type, "")
                if url:
                    enabled_sources.append((sport_type, url))

        total_sources = max(1, len(enabled_sources))
        _safe_progress_update(progress_cb, 10, f"Loading sports feeds ({len(enabled_sources)} enabled)...")

        import urllib.request
        for idx, (sport_type, url) in enumerate(enabled_sources):
            base = int(10 + (idx / float(total_sources)) * 60)
            _safe_progress_update(progress_cb, base, f"Fetching {sport_type.upper()} feed ({idx + 1}/{total_sources})...")
            try:
                request = urllib.request.Request(url, headers=headers)
                with urllib.request.urlopen(request, timeout=10) as response:
                    data = json.loads(response.read())
                    channels, programs = parse_sports_data(data, sport_type)
                    all_channels.extend(channels)
                    all_programs.extend(programs)
                _safe_progress_update(progress_cb, min(70, base + 5), f"Loaded {sport_type.upper()}: +{len(channels)} channels, +{len(programs)} programs")
            except Exception:
                _safe_progress_update(progress_cb, min(70, base + 5), f"Skipped {sport_type.upper()} (fetch error)")
                continue

        if all_channels and all_programs:
            save_sports_cache(all_channels, all_programs)

        _safe_progress_update(progress_cb, 75, f"Sports loaded: {len(all_channels)} channels, {len(all_programs)} programs")
        return all_channels, all_programs
    except Exception:
        return [], []


def load_sport_search_cache():
    profile = xbmcvfs.translatePath('special://profile')
    cache_path = os.path.join(profile, 'addon_data', 'plugin.video.madtitansports', 'pvr_sport_search_cache.json')
    try:
        if os.path.exists(cache_path):
            with open(cache_path, 'r', encoding='utf-8') as f:
                content = f.read().strip()
                if content:
                    data = json.loads(content)
                    if isinstance(data, list) and len(data) > 0:
                        return data
    except Exception:
        pass
    return []


def _format_query_display(entry):
    query = entry.get('query', 'Unknown')
    items = entry.get('items', [])
    item_count = len(items)
    cache_time = entry.get('time', 0)
    try:
        dt = datetime.fromtimestamp(cache_time, tz=timezone.utc)
        time_str = dt.strftime('%b %d, %H:%M')
    except Exception:
        time_str = ''
    return f"{query} ({item_count}) [COLOR grey]{time_str}[/COLOR]"


def _parse_sport_search_cache(items, query):
    channels = []
    programs = []
    default_icon = 'special://home/addons/plugin.video.jet_guide/resources/skins/default/720p/media/sports_icon.png'

    try:
        import tzlocal
        local_tz = tzlocal.get_localzone()
    except Exception:
        local_tz = datetime.now().astimezone().tzinfo
    now = datetime.now(local_tz)

    for idx, item in enumerate(items):
        if item.get('type') != 'item':
            continue
        title = item.get('title', '').replace('[COLOR]', '').replace('[/COOR]', '')
        summary = item.get('summary', title)
        fanart = item.get('fanart') or item.get('thumbnail') or default_icon
        extractors = item.get('sportjetextractors', [])

        if not extractors:
            continue

        urls = []
        stream_names = []
        for ext in extractors:
            addr = ext.get('address', '')
            name = ext.get('name', '')
            is_links = ext.get('links', False)
            if addr:
                if is_links:
                    addr = f"links://{addr}"
                plugin_url = f"plugin://plugin.video.madtitansports/sportjetextractors/play?urls={urllib.parse.quote(addr)}"
                urls.append(plugin_url)
                if name:
                    stream_names.append(name)
                else:
                    stream_names.append(f"Stream {len(stream_names)+1}")

        if not urls:
            continue

        channel_id = f"search_{query}_{idx}"
        channel = {
            'name': summary,
            'tvg_id': channel_id,
            'logo': fanart,
            'group': 'SEARCH',
            'url': urls[0],
            'all_links': urls,
            'stream_names': stream_names,
        }
        channels.append(channel)

        start_time = now
        stop_time = now + timedelta(hours=3)

        program = {
            'channel': channel_id,
            'start': start_time,
            'stop': stop_time,
            'title': title,
            'desc': f"Available on: {len(urls)} sources",
            'category': ['SEARCH'],
            'icon': {'src': fanart},
        }
        programs.append(program)

    return channels, programs


def show_sports_guide(acquire_dialog_lock, release_dialog_lock, addon, progress_cb=None):
    if not acquire_dialog_lock('show_sports_guide'):
        xbmcgui.Dialog().ok("Error", "Another process is running. Please wait.")
        return

    try:
        xbmc.executebuiltin('Dialog.Close(all, true)')
        xbmc.sleep(200)

        progress = xbmcgui.DialogProgress()
        progress.create('Loading Sports Guide', 'Fetching sports data...')
        progress.update(0)

        channels, programs = parse_sports_json(progress_cb=progress_cb, addon=addon)
        progress.update(50, 'Filtering sports events...')

        try:
            import tzlocal
            local_tz = tzlocal.get_localzone()
        except Exception:
            local_tz = datetime.now().astimezone().tzinfo
        now = datetime.now(local_tz)
        today = now.date()

        dlg = xbmcgui.Dialog()

        search_cache = load_sport_search_cache()
        mode_options = ["[COLOR yellow]Today's Games[/COLOR]", "[COLOR limegreen]Live Now[/COLOR]"]
        search_options = []
        if search_cache:
            search_options.append("[COLOR cyan]-- Previous Searches --[/COLOR]")
            for entry in search_cache:
                search_options.append(_format_query_display(entry))
            search_options.append("")

        all_options = mode_options + search_options
        choice = dlg.select("Show Sports", all_options)

        num_search_entries = len(search_cache)
        header_idx = 2
        separator_idx = num_search_entries + 3
        search_start_idx = 3

        if choice == -1:
            progress.close()
            return

        def is_today_local(dt):
            try:
                return dt.astimezone(local_tz).date() == today
            except Exception:
                return False

        def is_live_now(p):
            try:
                start = p.get('start')
                stop = p.get('stop')
                return start and stop and start.astimezone(local_tz) <= now <= stop.astimezone(local_tz)
            except Exception:
                return False

        if choice == 0:
            programs = [p for p in programs if p.get('start') and is_today_local(p['start'])]
        elif choice == 1:
            programs = [p for p in programs if is_live_now(p)]
        elif choice == header_idx or choice == separator_idx:
            progress.close()
            return
        elif search_start_idx <= choice < separator_idx and search_cache:
            progress.close()
            search_idx = choice - search_start_idx
            if search_idx < 0 or search_idx >= num_search_entries:
                return
            cache_entry = search_cache[search_idx]
            query = cache_entry.get('query', '')
            items = cache_entry.get('items', [])

            if not items:
                xbmcgui.Dialog().ok('Sports Guide', f'No results found for "{query}"')
                return

            progress2 = xbmcgui.DialogProgress()
            progress2.create('Loading Sports Guide', f'Searching for: {query}')
            progress2.update(0)

            from epggrid import EPGGrid
            addon_path = addon.getAddonInfo('path')
            skin_xml = os.path.join(addon_path, 'resources', 'skins', 'default', '720p', 'tuepg.guide.experimental.xml')
            if not os.path.exists(skin_xml):
                progress2.close()
                raise Exception(f"EPG skin XML not found at {skin_xml}")

            progress2.update(50, 'Processing search results...')
            channels_cache, programs_cache = _parse_sport_search_cache(items, query)
            progress2.update(80, 'Preparing guide...')

            if not channels_cache or not programs_cache:
                progress2.close()
                xbmcgui.Dialog().ok('Sports Guide', f'No results found for "{query}"')
                return

            channel_ids_cache = set(p['channel'] for p in programs_cache)
            channels_cache = [c for c in channels_cache if c.get('tvg_id') in channel_ids_cache]

            progress2.update(100)
            progress2.close()

            window = EPGGrid('tuepg.guide.experimental.xml', addon_path, channels=channels_cache, programs=programs_cache, is_sports_view=True)
            xbmc.sleep(100)
            window.doModal()
            del window
            return

        channel_ids = set(p['channel'] for p in programs)
        channels = [c for c in channels if c.get('tvg_id') in channel_ids]

        progress.update(75, 'Preparing guide...')
        if not channels or not programs:
            progress.close()
            xbmcgui.Dialog().ok('Sports Guide', 'No enabled sports events found')
            return

        from epggrid import EPGGrid
        addon_path = addon.getAddonInfo('path')
        skin_xml = os.path.join(addon_path, 'resources', 'skins', 'default', '720p', 'tuepg.guide.experimental.xml')
        if not os.path.exists(skin_xml):
            progress.close()
            raise Exception(f"EPG skin XML not found at {skin_xml}")

        window = EPGGrid('tuepg.guide.experimental.xml', addon_path, channels=channels, programs=programs, is_sports_view=True)
        xbmc.sleep(100)
        progress.update(100)
        progress.close()
        window.doModal()
        del window

    except Exception as e:
        if 'progress' in locals():
            progress.close()
        xbmcgui.Dialog().ok("Error", f"Failed to load sports guide: {str(e)}")
    finally:
        release_dialog_lock('show_sports_guide')
