import json
import threading
from collections import defaultdict
from datetime import datetime

import xbmc
import xbmcaddon
import xbmcgui
import xbmcvfs

from cache import get_cache_files, load_cache
from jet_parser import get_active_guide
from tools import debug_log


def start_ticker_updates(self):
    self.ticker_thread = threading.Thread(target=self.update_ticker)
    self.ticker_thread.daemon = True
    self.ticker_thread.start()


def remove_widget_by_link(self, widget_link):
    """Remove a widget from widgets.json by its link and refresh the list."""
    widgets_path = xbmcvfs.translatePath("special://userdata/addon_data/plugin.video.jet_guide/widgets.json")
    try:
        with xbmcvfs.File(widgets_path, "r") as f:
            links = json.loads(f.read())
        new_links = [
            w
            for w in links
            if not ((w.get("link") == widget_link) or (w.get("source_folder") == widget_link))
        ]
        with xbmcvfs.File(widgets_path, "w") as f:
            f.write(json.dumps(new_links, indent=2))
        xbmcgui.Dialog().notification("Widget Removed", "The widget has been deleted.", xbmcgui.NOTIFICATION_INFO, 3000)
        self.load_pinned_widgets()
    except Exception as e:
        xbmcgui.Dialog().notification("Error", f"Failed to remove widget: {e}", xbmcgui.NOTIFICATION_ERROR, 3000)


def update_ticker(self):
    main_addon = xbmcaddon.Addon()
    if not main_addon.getSettingBool('livescore_alerts_enabled'):
        self.ticker_control.setText("LiveScore Alerts disabled")
        debug_log("LiveScore Alerts disabled, ticker not updated", level=xbmc.LOGINFO)
        return
    while self.ticker_running and not xbmc.Monitor().abortRequested():
        try:
            games = self.fetch_games()
            if games:
                messages = [f"{title}: {g['score']} ({g['status']})" for title, g in games.items()]
                ticker_text = "  |  ".join(messages)
                self.ticker_control.setText(ticker_text)
            else:
                self.ticker_control.setText("No live scores available")
                debug_log("No live scores available for ticker", level=xbmc.LOGINFO)
        except Exception as e:
            debug_log(f"Ticker update error: {str(e)}", level=xbmc.LOGERROR)
            self.ticker_control.setText("Error fetching scores")
        xbmc.sleep(5 * 60)


def _format_epg_time(dt):
    """Format a datetime as 'H:MM AM/PM' without a leading zero on the hour."""
    try:
        text = dt.strftime('%I:%M %p')
        if text.startswith('0'):
            text = text[1:]
        return text
    except Exception:
        return ''


def _load_epg_preview_data(channel_ids):
    """
    Build a lookup of current/upcoming EPG data for the supplied channel ids.

    Returns a dict mapping channel_id -> (title, time_label, status).
    If no EPG cache exists, every id maps to a "no data" message so the
    user is prompted to run an EPG update.
    """
    no_data = {cid: ("No data available", "Run EPG update", "") for cid in channel_ids}
    try:
        cache_files = get_cache_files(get_active_guide())
        cached_data, _ = load_cache(cache_files['xmltv'], cache_files['xmltv_time'])
        if not cached_data:
            return no_data

        now = datetime.now().astimezone()
        channel_programs = defaultdict(list)
        for prog in cached_data:
            ch = prog.get('channel')
            if ch not in channel_ids:
                continue
            start = prog.get('start')
            stop = prog.get('stop')
            if not start or not stop:
                continue
            if stop < now:
                continue
            channel_programs[ch].append((start, stop, prog))

        result = {}
        for ch in channel_ids:
            progs = channel_programs.get(ch, [])
            if not progs:
                result[ch] = ("No data available", "Run EPG update", "")
                continue
            progs.sort(key=lambda x: x[0])
            start, stop, prog = progs[0]
            title = prog.get('title') or 'No Title'
            start_str = _format_epg_time(start)
            stop_str = _format_epg_time(stop)
            if start <= now < stop:
                result[ch] = (title, f"{start_str} - {stop_str}", "LIVE")
            else:
                result[ch] = (title, f"Next: {start_str}", "NEXT")
        return result
    except Exception as e:
        debug_log(f"Error loading EPG preview data: {e}", xbmc.LOGERROR)
        return no_data


def load_last_watched_channels(self, last_watched_manager):
    """Load and display last watched channels"""
    if not self.last_watched_list and not getattr(self, 'last_watched_preview_list', None):
        return

    try:
        if self.last_watched_list:
            self.last_watched_list.reset()
        preview_list = getattr(self, 'last_watched_preview_list', None)
        if preview_list:
            preview_list.reset()
        channels = last_watched_manager.load_last_watched()

        # Pre-load current/next EPG data for the last watched channels
        epg_lookup = {}
        if preview_list:
            channel_ids = {channel.get('tvg_id', '') for channel in channels if channel.get('tvg_id')}
            if channel_ids:
                epg_lookup = _load_epg_preview_data(channel_ids)

        for channel in channels:
            list_item = xbmcgui.ListItem(channel.get('name', 'Unknown'))
            list_item.setArt({'icon': channel.get('logo', '')})
            list_item.setProperty('channel_id', channel.get('tvg_id', ''))
            if self.last_watched_list:
                self.last_watched_list.addItem(list_item)

            if preview_list:
                preview_item = xbmcgui.ListItem(channel.get('name', 'Unknown'))
                preview_item.setArt({'icon': channel.get('logo', '')})
                preview_item.setProperty('channel_id', channel.get('tvg_id', ''))
                ch_id = channel.get('tvg_id', '')
                title, time_label, status = epg_lookup.get(
                    ch_id, ("No data available", "Run EPG update", "")
                )
                preview_item.setProperty('epg_title', title)
                preview_item.setProperty('epg_time', time_label)
                preview_item.setProperty('epg_status', status)
                preview_list.addItem(preview_item)

    except Exception:
        xbmcgui.Dialog().notification('Error', 'Failed to load recent channels')


def load_favorites_preview(self, favorites_manager, parse_m3u8, m3u8_path):
    """Load favorite channels into the Favorites preview strip."""
    preview_list = getattr(self, 'favorites_preview_list', None)
    if not preview_list:
        return

    try:
        preview_list.reset()
        favorite_ids = favorites_manager.load_favorites()
        if not favorite_ids:
            return

        channels = parse_m3u8(m3u8_path)
        channel_map = {c.get('tvg_id'): c for c in channels if c.get('tvg_id')}

        channel_ids = {fid for fid in favorite_ids if fid}
        epg_lookup = _load_epg_preview_data(channel_ids) if channel_ids else {}

        for fid in favorite_ids:
            channel = channel_map.get(fid)
            if not channel:
                # Skip favorites that no longer exist in the current M3U8
                continue
            name = channel.get('name', fid)
            logo = channel.get('logo', '')
            preview_item = xbmcgui.ListItem(name)
            preview_item.setArt({'icon': logo})
            preview_item.setProperty('channel_id', fid)
            title, time_label, status = epg_lookup.get(
                fid, ("No data available", "Run EPG update", "")
            )
            preview_item.setProperty('epg_title', title)
            preview_item.setProperty('epg_time', time_label)
            preview_item.setProperty('epg_status', status)
            preview_list.addItem(preview_item)

    except Exception as e:
        debug_log(f"Error loading favorites preview: {e}", xbmc.LOGERROR)



def play_last_watched(self, channel_id, parse_m3u8, m3u8_path):
    """Play a channel from last watched"""
    try:
        channels = parse_m3u8(m3u8_path)
        channel = next((c for c in channels if c['tvg_id'] == channel_id), None)
        if not channel:
            xbmcgui.Dialog().notification('Error', 'Channel not found')
            return

        list_item = xbmcgui.ListItem(channel['name'])
        list_item.setArt({'icon': channel.get('logo', '')})
        url = channel['url']
        if '|' in url:
            url = url.split('|')[0].strip()

        xbmc.executebuiltin('Dialog.Close(busydialog)')
        xbmc.Player().play(url, list_item)

    except Exception as e:
        xbmcgui.Dialog().ok("Error", f"Failed to play channel: {str(e)}")
