import xbmc
import xbmcgui
import xbmcaddon
import xbmcvfs
from datetime import datetime, timedelta
import json
import urllib.parse
from typing import Dict, List, Any

try:
    from themes import apply_theme_to_window
except ImportError:
    def apply_theme_to_window(window):
        pass  # No theming available

from analytics import track

try:
    from ai_ui import show_ai_search
except ImportError:
    show_ai_search = None


# Quick filter definitions: one-click filters shown before the search keyboard.
# Each filter narrows results to a known content type by matching channel group
# and/or program category keywords (case-insensitive substring match).
QUICK_FILTERS = {
    'all': {
        'label': 'All',
        'group_keywords': [],
        'category_keywords': [],
    },
    'live': {
        'label': 'Live',
        'group_keywords': ['live', '24/7', '24-7'],
        'category_keywords': [],
    },
    'sports': {
        'label': 'Sports',
        'group_keywords': ['sport', 'espn', 'nfl', 'nba', 'nhl', 'mlb', 'mls', 'ncaa',
                           'football', 'basketball', 'baseball', 'hockey', 'soccer',
                           'racing', 'pga', 'ufc', 'boxing', 'tennis', 'golf'],
        'category_keywords': ['sport', 'game', 'match'],
    },
    'movies': {
        'label': 'Movies',
        'group_keywords': ['movie', 'film', 'cinema', 'flick', 'hollywood', 'imax'],
        'category_keywords': ['movie', 'film', 'cinema'],
    },
    'kids': {
        'label': 'Kids',
        'group_keywords': ['kids', 'child', 'children', 'cartoon', 'nick', 'disney',
                           'nick jr', 'nickelodeon', 'baby', 'preschool', 'junior'],
        'category_keywords': ['kids', 'children', 'child', 'cartoon', 'animated'],
    },
    'news': {
        'label': 'News',
        'group_keywords': ['news', 'cnn', 'bbc', 'fox news', 'msnbc', 'abc news',
                           'cnbc', 'bloomberg', 'al jazeera', 'reuters', 'ap',
                           'local news', 'world news', 'headline'],
        'category_keywords': ['news', 'headline', 'current affairs'],
    },
}

class SearchWindow(xbmcgui.WindowXML):
    def __init__(self, xml_file: str, addon_path: str, channels: List[Dict[str, Any]] = None, programs: List[Dict[str, Any]] = None, return_selection: bool = False, quick_filter: str = 'all'):
        super().__init__(xml_file, addon_path, "default")
        self.channels = channels or []
        self.programs = programs or []
        self.initial_quick_filter = quick_filter if quick_filter in QUICK_FILTERS else 'all'
        self.list_control = None
        self.search_term = ""
        self.current_time = datetime.now().astimezone()
        self.return_selection = return_selection  # If True, return selected stream instead of playing
        self.selected_stream = None  # To store selected stream when return_selection is True
        
        # Get addon for settings
        self.addon = xbmcaddon.Addon()
        
        # Paths for saved searches
        self.profile_path = xbmcvfs.translatePath(self.addon.getAddonInfo('profile'))
        self.saved_searches_path = self.profile_path + "saved_searches.json"
        self.search_history_path = self.profile_path + "search_history.json"
        self.max_history = 10  # Keep last 10 searches
        
        # Get unique categories from channels and programs
        self.categories = self._get_categories()
    
    def _get_categories(self) -> List[str]:
        """Extract unique categories from channels and programs"""
        categories = set()
        for channel in self.channels:
            group = channel.get('group', '')
            if group:
                categories.add(group)
        for program in self.programs:
            cat = program.get('category', '')
            if cat:
                if isinstance(cat, list):
                    for c in cat:
                        categories.add(c)
                else:
                    categories.add(cat)
        return sorted(list(categories))
    
    def _get_saved_searches(self) -> List[Dict]:
        """Load saved searches from file"""
        try:
            if xbmcvfs.exists(self.saved_searches_path):
                with xbmcvfs.File(self.saved_searches_path, 'r') as f:
                    return json.loads(f.read())
        except Exception:
            pass
        return []
    
    def _save_saved_searches(self, searches: List[Dict]) -> bool:
        """Save searches to file"""
        try:
            with xbmcvfs.File(self.saved_searches_path, 'w') as f:
                f.write(json.dumps(searches, indent=2))
            return True
        except Exception:
            return False
    
    def set_quick_filter(self, filter_key: str):
        """Set the quick filter and re-run the current search immediately."""
        if filter_key not in QUICK_FILTERS:
            filter_key = 'all'
        self.setProperty('quick_filter', filter_key)
        if self.search_term:
            self._do_search()
        else:
            self.setProperty('current_filter_label', QUICK_FILTERS[filter_key]['label'])

    def _save_current_search(self):
        """Save the current search term and filters"""
        dialog = xbmcgui.Dialog()
        
        # Ask for a name for this saved search
        name = dialog.input("Enter a name for this saved search", defaultt=self.search_term)
        if not name:
            return
        
        saved_searches = self._get_saved_searches()
        
        # Check for duplicate name
        for s in saved_searches:
            if s.get('name') == name:
                dialog.ok("Error", "A saved search with this name already exists.")
                return
        
        # Get current filter selections
        time_filter = self.getProperty('time_filter') if hasattr(self, 'getProperty') else 'all'
        category_filter = self.getProperty('category_filter') if hasattr(self, 'getProperty') else 'all'
        quick_filter = self.getProperty('quick_filter') if hasattr(self, 'getProperty') else 'all'

        saved_search = {
            'name': name,
            'search_term': self.search_term,
            'time_filter': time_filter,
            'category_filter': category_filter,
            'quick_filter': quick_filter,
        }
        
        saved_searches.append(saved_search)
        
        if self._save_saved_searches(saved_searches):
            dialog.notification("Saved", f"Search '{name}' saved", xbmcgui.NOTIFICATION_INFO, 2000)
        else:
            dialog.ok("Error", "Failed to save search.")

    def _get_search_history(self) -> List[str]:
        """Load search history from file"""
        try:
            if xbmcvfs.exists(self.search_history_path):
                with xbmcvfs.File(self.search_history_path, 'r') as f:
                    return json.loads(f.read())
        except Exception:
            pass
        return []

    def _add_to_history(self, search_term: str):
        """Add search term to history"""
        if not search_term:
            return
        
        history = self._get_search_history()
        
        # Remove if already exists (to move to top)
        if search_term in history:
            history.remove(search_term)
        
        # Add to beginning
        history.insert(0, search_term)
        
        # Keep only last N searches
        history = history[:self.max_history]
        
        try:
            with xbmcvfs.File(self.search_history_path, 'w') as f:
                f.write(json.dumps(history))
        except Exception:
            pass

    def _clear_history(self):
        """Clear search history"""
        dialog = xbmcgui.Dialog()
        if dialog.yesno("Clear History", "Are you sure you want to clear search history?"):
            try:
                if xbmcvfs.exists(self.search_history_path):
                    xbmcvfs.delete(self.search_history_path)
                dialog.notification("Cleared", "Search history cleared", xbmcgui.NOTIFICATION_INFO, 2000)
            except Exception:
                pass
    
    def _show_history_menu(self):
        """Show full search history with options to use or clear"""
        dialog = xbmcgui.Dialog()
        history = self._get_search_history()
        
        if not history:
            dialog.ok("Search History", "No search history yet.")
            return
        
        while True:
            options = [h for h in history]
            options.append("[Clear All History]")
            options.append("[Done]")
            
            choice = dialog.select("Search History", options)
            
            if choice == -1 or choice == len(options) - 1:
                break
            
            if choice == len(options) - 2:
                # Clear all history
                self._clear_history()
                break
            
            # Use this search term
            self.search_term = history[choice]
            self.setProperty('time_filter', 'all')
            self.setProperty('category_filter', 'all')
            self.setProperty('quick_filter', 'all')
            self._do_search()
            break
    
    def _show_saved_searches_menu(self):
        """Show menu to load or manage saved searches"""
        dialog = xbmcgui.Dialog()
        saved_searches = self._get_saved_searches()
        
        if not saved_searches:
            dialog.ok("Saved Searches", "No saved searches yet.")
            return
        
        while True:
            options = [s['name'] for s in saved_searches]
            options.append("[Delete a Saved Search]")
            options.append("[Done]")
            
            choice = dialog.select("Saved Searches", options)
            
            if choice == -1 or choice == len(options) - 1:
                break
            
            if choice == len(options) - 2:
                # Delete a saved search
                self._delete_saved_search(saved_searches)
                saved_searches = self._get_saved_searches()
                continue
            
            # Load the saved search
            saved = saved_searches[choice]
            self.search_term = saved.get('search_term', '')
            self.setProperty('time_filter', saved.get('time_filter', 'all'))
            self.setProperty('category_filter', saved.get('category_filter', 'all'))
            self.setProperty('quick_filter', saved.get('quick_filter', 'all'))
            self._do_search()
            break
    
    def _delete_saved_search(self, saved_searches: List[Dict]):
        """Delete a saved search"""
        dialog = xbmcgui.Dialog()
        options = [s['name'] for s in saved_searches]
        options.append("Cancel")
        
        choice = dialog.select("Delete Saved Search", options)
        
        if choice == -1 or choice == len(options) - 1:
            return
        
        # Remove the search
        deleted_name = saved_searches.pop(choice)['name']
        
        if self._save_saved_searches(saved_searches):
            dialog.notification("Deleted", f"Search '{deleted_name}' deleted", xbmcgui.NOTIFICATION_INFO, 2000)
    
    def _get_time_filter_options(self) -> List[str]:
        """Get time filter options"""
        return ['all', 'now', 'later_today', 'tomorrow', 'this_week']
    
    def _get_time_filter_display(self, filter_key: str) -> str:
        """Get display name for time filter"""
        display = {
            'all': 'All Times',
            'now': 'Now Playing',
            'later_today': 'Later Today',
            'tomorrow': 'Tomorrow',
            'this_week': 'This Week'
        }
        return display.get(filter_key, filter_key)
    
    def _get_category_filter_options(self) -> List[str]:
        """Get category filter options"""
        return ['all'] + self.categories
    
    def _filter_by_time(self, program: Dict, time_filter: str) -> bool:
        """Check if program matches time filter"""
        if time_filter == 'all':
            return True
        
        start = program.get('start')
        if not start:
            return True  # Include if no start time
        
        if time_filter == 'now':
            # Currently playing (between start and stop)
            return start <= self.current_time <= program.get('stop', start + timedelta(hours=1))
        
        elif time_filter == 'later_today':
            # Later today (after now but before midnight)
            end_today = self.current_time.replace(hour=23, minute=59, second=59)
            return start > self.current_time and start <= end_today
        
        elif time_filter == 'tomorrow':
            # Tomorrow
            tomorrow = (self.current_time + timedelta(days=1)).replace(hour=0, minute=0, second=0)
            tomorrow_end = (tomorrow + timedelta(days=1))
            return start >= tomorrow and start < tomorrow_end
        
        elif time_filter == 'this_week':
            # This week (next 7 days)
            week_end = self.current_time + timedelta(days=7)
            return start >= self.current_time and start <= week_end
        
        return True
    
    def _filter_by_category(self, program: Dict, channel: Dict, category_filter: str) -> bool:
        """Check if program/channel matches category filter"""
        if category_filter == 'all':
            return True
        
        # Check program category
        program_cat = program.get('category', '')
        if program_cat:
            if isinstance(program_cat, list):
                if category_filter in program_cat:
                    return True
            elif program_cat.lower() == category_filter.lower():
                return True
        
        # Check channel group
        channel_group = channel.get('group', '')
        if channel_group and channel_group.lower() == category_filter.lower():
            return True
        
        return category_filter == 'all'
    
    def _show_quick_filter_menu(self) -> str:
        """Show the one-click quick filter selection (Live/Sports/Movies/Kids/News).

        Returns the chosen filter key, or 'all' if the user cancelled / picked All.
        """
        dialog = xbmcgui.Dialog()
        labels = [info['label'] for info in QUICK_FILTERS.values()]
        keys = list(QUICK_FILTERS.keys())

        current = self.getProperty('quick_filter') if hasattr(self, 'getProperty') else 'all'
        try:
            preselect = keys.index(current) if current in keys else 0
        except ValueError:
            preselect = 0

        choice = dialog.select("Quick Filter (optional)", labels, preselect=preselect)
        if choice < 0 or choice >= len(keys):
            return 'all'
        return keys[choice]

    def _match_quick_filter(self, channel: Dict, program: Dict, quick_filter: str) -> bool:
        """Return True if the channel/program satisfies the given quick filter.

        Uses case-insensitive substring matching against the channel's group
        and the program's category/title.
        """
        info = QUICK_FILTERS.get(quick_filter)
        if not info or quick_filter == 'all':
            return True

        group = (channel.get('group', '') or '').lower()
        title = (program.get('title', '') or '').lower() if program else ''
        cat = program.get('category', '') if program else ''
        if isinstance(cat, list):
            cat_str = ' '.join(cat).lower()
        else:
            cat_str = (cat or '').lower()

        group_keywords = info.get('group_keywords', [])
        category_keywords = info.get('category_keywords', [])

        for kw in group_keywords:
            if kw and kw in group:
                return True
            if kw and kw in title:
                return True
        for kw in category_keywords:
            if kw and kw in cat_str:
                return True
            if kw and kw in title:
                return True
        return False

    def _show_filter_menu(self):
        """Show filter selection menu"""
        dialog = xbmcgui.Dialog()
        
        # Time filter
        time_options = [
            "All Times",
            "Now Playing", 
            "Later Today",
            "Tomorrow",
            "This Week"
        ]
        
        current_time_filter = self.getProperty('time_filter') if hasattr(self, 'getProperty') else 'all'
        time_choice = dialog.select("Filter by Time", time_options)
        
        if time_choice == -1:
            return
        
        time_filters = ['all', 'now', 'later_today', 'tomorrow', 'this_week']
        time_filter = time_filters[time_choice]
        self.setProperty('time_filter', time_filter)
        
        # Category filter
        cat_options = ["All Categories"] + self.categories
        current_cat_filter = self.getProperty('category_filter') if hasattr(self, 'getProperty') else 'all'
        
        cat_choice = dialog.select("Filter by Category", cat_options)
        
        if cat_choice == -1:
            return
        
        cat_filters = ['all'] + self.categories
        category_filter = cat_filters[cat_choice]
        self.setProperty('category_filter', category_filter)
        
        # Re-run search with filters
        self._do_search()
    
    def _do_search(self):
        """Perform the search with current filters"""
        # Add to search history
        if self.search_term:
            self._add_to_history(self.search_term)

        self.list_control.reset()

        search_term = self.search_term.lower().strip()
        time_filter = self.getProperty('time_filter') if hasattr(self, 'getProperty') else 'all'
        category_filter = self.getProperty('category_filter') if hasattr(self, 'getProperty') else 'all'
        quick_filter = self.getProperty('quick_filter') if hasattr(self, 'getProperty') else 'all'

        # Build filter info string
        filters_applied = []
        if quick_filter and quick_filter != 'all':
            filters_applied.append(f"Type: {QUICK_FILTERS.get(quick_filter, {}).get('label', quick_filter)}")
            if not search_term and time_filter == 'all':
                filters_applied.append("Time: Today (live + upcoming)")
        if time_filter != 'all':
            filters_applied.append(f"Time: {self._get_time_filter_display(time_filter)}")
        if category_filter != 'all':
            filters_applied.append(f"Category: {category_filter}")

        filter_info = f" [COLOR grey]({', '.join(filters_applied)})[/COLOR]" if filters_applied else ""
        
        # Header with search term and filters
        if self.search_term:
            header = xbmcgui.ListItem(f'[COLOR gold]Search: "{self.search_term}"{filter_info}[/COLOR]')
        elif quick_filter and quick_filter != 'all':
            header = xbmcgui.ListItem(f'[COLOR gold]Quick: {QUICK_FILTERS[quick_filter]["label"]} Channels{filter_info}[/COLOR]')
        else:
            header = xbmcgui.ListItem(f'[COLOR gold]Search Results[/COLOR]')
        self.list_control.addItem(header)

        found_channels = []
        found_programs = []

        # Search channels
        for channel in self.channels:
            if search_term and search_term in channel['name'].lower():
                if not self._match_quick_filter(channel, None, quick_filter):
                    continue
                found_channels.append(channel)
            elif not search_term and quick_filter and quick_filter != 'all':
                if self._match_quick_filter(channel, None, quick_filter):
                    found_channels.append(channel)

        # When launched from a home quick-filter chip with no manual time filter
        # and no search term, only include programs that fall within "today"
        # (so live-now programs and the rest of today's schedule show, but not
        # programs that ended hours ago or start days from now). Users can
        # still widen this by pressing the Filters button.
        quick_filter_active = bool(quick_filter and quick_filter != 'all')
        narrow_to_today = (
            quick_filter_active
            and not search_term
            and time_filter == 'all'
        )
        if narrow_to_today:
            day_start = self.current_time - timedelta(hours=2)
            day_end = (self.current_time + timedelta(days=1)).replace(hour=0, minute=0, second=0)

        # Search programs with filters
        for program in self.programs:
            # Apply time filter
            if not self._filter_by_time(program, time_filter):
                continue

            # Apply "today" window for quick-filter listings
            if narrow_to_today:
                start = program.get('start')
                stop = program.get('stop')
                if start is not None and stop is not None:
                    # Skip programs that ended before day_start or start after day_end
                    if stop < day_start or start > day_end:
                        continue
                elif start is not None and start > day_end:
                    continue

            # Check if program matches search term
            if search_term and search_term not in program.get('title', '').lower():
                continue

            # Find matching channel
            channel = next((c for c in self.channels if c.get('tvg_id') == program.get('channel')), None)
            if not channel:
                continue

            # Apply quick filter (content type)
            if not self._match_quick_filter(channel, program, quick_filter):
                continue

            # Apply category filter
            if not self._filter_by_category(program, channel, category_filter):
                continue

            found_programs.append({
                'program': program,
                'channel': channel
            })
        
        # Sort programs by start time
        found_programs.sort(key=lambda x: x['program'].get('start', datetime.now()))
        
        # Add results
        if found_channels:
            section = xbmcgui.ListItem(f'[COLOR yellow]Channels ({len(found_channels)})[/COLOR]')
            self.list_control.addItem(section)
            
            for channel in found_channels:
                name = f"[COLOR yellow]► {channel['name']}[/COLOR]"
                item = xbmcgui.ListItem(name)
                item.setArt({'icon': channel.get('logo', ''), 'thumb': channel.get('logo', '')})
                item.setProperty('type', 'channel')
                item.setProperty('channel_id', channel.get('tvg_id', ''))
                self.list_control.addItem(item)
        
        if found_programs:
            section = xbmcgui.ListItem(f'[COLOR lime]Programs ({len(found_programs)})[/COLOR]')
            self.list_control.addItem(section)
            
            for result in found_programs:
                program = result['program']
                channel = result['channel']
                start_time = program.get('start')
                time_str = start_time.strftime('%I:%M %p') if start_time else 'Unknown'
                day_str = ''
                if start_time:
                    if start_time.date() > self.current_time.date():
                        day_str = start_time.strftime('%a ')
                    elif start_time.date() == (self.current_time + timedelta(days=1)).date():
                        day_str = 'Tomorrow '
                
                name = f"[COLOR lime]{program.get('title', 'Unknown')}[/COLOR] on {channel.get('name', 'Unknown')} at {day_str}{time_str}"
                
                item = xbmcgui.ListItem(name)
                item.setArt({'icon': channel.get('logo', ''), 'thumb': channel.get('logo', '')})
                item.setProperty('type', 'program')
                item.setProperty('channel_id', channel.get('tvg_id', ''))
                self.list_control.addItem(item)
        
        if not found_channels and not found_programs:
            no_results = xbmcgui.ListItem('[COLOR red]No matches found[/COLOR]')
            self.list_control.addItem(no_results)
        
        self.setFocusId(100)
    
    def onInit(self):
        try:
            # Apply theme colors
            apply_theme_to_window(self)
            
            # Get list control
            self.list_control = self.getControl(100)

            # If launched with a quick filter from the home screen, list
            # matching channels immediately (no keyboard prompt). The user
            # can still press the New Search button for the full search UI.
            if self.initial_quick_filter and self.initial_quick_filter != 'all':
                self.setProperty('quick_filter', self.initial_quick_filter)
                self.setProperty('time_filter', 'all')
                self.setProperty('category_filter', 'all')
                self.search_term = ''
                self._do_search()
                self.setFocusId(100)
                return

            # Show empty list with hint, then trigger new search
            # Don't show menu dialog automatically - too confusing with both window and dialog open
            hint_item = xbmcgui.ListItem('[COLOR gray]Press Enter or Context Menu to start a new search[/COLOR]')
            hint_item.setProperty('type', 'hint')
            self.list_control.addItem(hint_item)
            self.setFocusId(100)

            # Directly show the keyboard for new search (most common use case)
            self._do_new_search()

        except Exception as e:
            xbmcgui.Dialog().ok("Error", f"Failed to initialize search: {str(e)}")
            self.close()
    
    def _show_search_menu(self):
        """Show the search options menu"""
        dialog = xbmcgui.Dialog()
        
        # Check for search history
        history = self._get_search_history()
        
        # Build options list
        options = []
        
        # Show recent searches if any
        if history:
            options.append("-- Recent --")
            for h in history[:5]:
                options.append(f"  {h}")
            options.append("")
        
        options.append("New Search...")
        options.append("Full History")
        options.append("Saved Searches")
        options.append("Cancel")
        
        choice = dialog.select("Search", options)
        
        if choice == -1:
            self.close()
            return
        
        # Calculate indices properly
        num_history = len(history[:5]) if history else 0
        new_search_idx = num_history + 2 if history else 1
        
        # Handle selection
        if history and choice > 0 and choice <= num_history:
            # Selected a recent search
            idx = choice - 1
            if 0 <= idx < num_history:
                self.search_term = history[:5][idx]
                self.setProperty('time_filter', 'all')
                self.setProperty('category_filter', 'all')
                self._do_search()
                return
        elif choice == new_search_idx:
            # New Search
            self._do_new_search()
            return
        elif choice == new_search_idx + 1:
            # Full history
            self._show_history_menu()
            return
        elif choice == new_search_idx + 2:
            # Saved searches
            self._show_saved_searches_menu()
            return
        
        # Default: close
        self.close()

    def _do_new_search(self):
        """Handle new search input"""
        dialog = xbmcgui.Dialog()

        keyboard = xbmc.Keyboard('', 'Search Channels and Programs')
        keyboard.doModal()

        if not keyboard.isConfirmed():
            # Go back to search menu
            self._show_search_menu()
            return

        self.search_term = keyboard.getText().strip()

        if not self.search_term:
            # Go back to search menu
            self._show_search_menu()
            return

        # Ask if user wants to set filters
        filter_choice = dialog.yesno("Search", "Would you like to set time/category filters?", "No", "Yes - Set Filters")

        if not filter_choice:
            self.setProperty('time_filter', 'all')
            self.setProperty('category_filter', 'all')
            self._do_search()
        else:
            self._show_filter_menu()
    
    def play_channel(self, channel_id: str):
        """Play a channel directly or return selection if return_selection is True"""
        try:
            # Find the channel
            channel = next((c for c in self.channels if c.get('tvg_id') == channel_id), None)
            if not channel:
                return

            # If return_selection mode, just store the channel and close
            if self.return_selection:
                self.selected_stream = {
                    'link': channel.get('url', '') or channel.get('stream_url', ''),
                    'title': channel.get('name', 'Unknown'),
                    'headers': {}
                }
                self.close()
                return

            # Build the list of available streams for this channel.
            # Supports three channel shapes:
            #   1) 'all_links' + 'stream_names' (sports / JSON-loaded channels)
            #   2) 'url' with '|'-separated streams (each optionally named in (parens))
            #   3) single 'url'
            stream_links = []
            stream_labels = []

            all_links = channel.get('all_links') or []
            all_names = channel.get('stream_names') or []
            if all_links:
                for idx, link in enumerate(all_links):
                    if not link:
                        continue
                    label = all_names[idx] if idx < len(all_names) and all_names[idx] else f"Stream {len(stream_links) + 1}"
                    stream_links.append(link)
                    stream_labels.append(str(label))
            else:
                raw_url = channel.get('url', '') or channel.get('stream_url', '')
                if '|' in raw_url:
                    parts = [s.strip() for s in raw_url.split('|') if s.strip()]
                    for part in parts:
                        if '(' in part and ')' in part:
                            label = part[part.rindex('(') + 1:part.rindex(')')]
                            url = part[:part.rindex('(')].strip()
                        else:
                            label = f"Stream {len(stream_links) + 1}"
                            url = part
                        if url:
                            stream_links.append(url)
                            stream_labels.append(label)
                elif raw_url:
                    stream_links.append(raw_url)
                    stream_labels.append("Stream 1")

            if not stream_links:
                xbmcgui.Dialog().ok("Error", "No stream URL found for this channel.")
                return

            # Multiple streams: show a picker so the user picks which one to play.
            if len(stream_links) > 1:
                choice = xbmcgui.Dialog().select("Choose Stream", stream_labels)
                if choice < 0:
                    return  # User cancelled - stay in the search window
                url = stream_links[choice]
            else:
                url = stream_links[0]

            if not url:
                xbmcgui.Dialog().ok("Error", "No stream URL found for this channel.")
                return

            # Create list item
            list_item = xbmcgui.ListItem(channel.get('name', 'Unknown'))
            list_item.setArt({'icon': channel.get('logo', '')})

            # Close dialog and play
            xbmc.executebuiltin('Dialog.Close(busydialog)')
            self.close()

            track(event="play", channel_name=channel.get('name', ''), channel_id=channel.get('tvg_id', ''), url=url, source="search")
            # Cancel any running YouTube sequential playback before playing new content
            try:
                from youtube_guide import cancel_youtube_playback
                cancel_youtube_playback()
            except ImportError:
                pass

            xbmc.Player().play(url, list_item)

        except Exception as e:
            xbmcgui.Dialog().ok("Error", f"Failed to play channel: {str(e)}")
    
    def onClick(self, control_id):
        try:
            if control_id == 100:
                pos = self.list_control.getSelectedPosition()
                item = self.list_control.getSelectedItem()
                
                item_type = item.getProperty('type')
                if item_type in ['channel', 'program']:
                    channel_id = item.getProperty('channel_id')
                    self.play_channel(channel_id)
            
            # Filter button (if exists in skin)
            elif control_id == 101:
                self._show_filter_menu()
            
            # Save search button (if exists in skin)
            elif control_id == 102:
                if self.search_term:
                    self._save_current_search()
            
            # New search button (if exists in skin)
            elif control_id == 103:
                self._show_search_menu()
            
            # Filter button
            elif control_id == 104:
                self._show_filter_menu()
            
            # Saved searches button
            elif control_id == 105:
                self._show_saved_searches_menu()

            elif control_id == 106:
                self._show_history_menu()

            elif control_id == 107:
                if show_ai_search:
                    show_ai_search(self.channels)
                else:
                    xbmcgui.Dialog().ok("AI Assistant", "AI Assistant module not available.")
        except Exception as e:
            xbmcgui.Dialog().ok("Error", f"Error handling click: {str(e)}")
    
    def onAction(self, action):
        try:
            action_id = action.getId()
            
            # Close on back/menu buttons
            if action_id in [xbmcgui.ACTION_PREVIOUS_MENU, xbmcgui.ACTION_NAV_BACK, 92]:
                self.close()
            
            # Enter key - only start new search if no search term yet AND the
            # list has no real results (avoids stealing the Enter from a focused
            # result row in quick-filter mode).
            elif action_id == 7 or action_id == 58:  # Enter or Select
                if not self.search_term and not self.initial_quick_filter:
                    self._do_new_search()
            
            # Context menu for additional options
            elif action_id == 117:  # Context menu
                dialog = xbmcgui.Dialog()
                options = ["New Search", "Saved Searches", "Set Filters", "Save Current Search"]
                if show_ai_search:
                    options.append("AI Search")
                choice = dialog.select("Options", options)

                if choice == 0:
                    self._do_new_search()  # Go directly to keyboard
                elif choice == 1:
                    self._show_saved_searches_menu()
                elif choice == 2:
                    self._show_filter_menu()
                elif choice == 3:
                    if self.search_term:
                        self._save_current_search()
                elif choice == 4 and show_ai_search:
                    show_ai_search(self.channels)
        
        except Exception as e:
            xbmcgui.Dialog().ok("Error", f"Error handling action: {str(e)}")
