# wcs/ai/DialogMyCinema.py
"""
MyCinema Dialog - Kino budoucnosti.

Rozširuje MyTV dialog pro správu filmových kin místo TV kanálu se seriály.
Plnohodnotný Apple TV layout adaptovaný pro filmy.

Modulární architektura:
- Dědí z MyTVDialog
- Přepisuje metody specifické pro filmy
- Používá sdílený AddMediaDialog s media_type='cinema'
- Hero zona zobrazuje první film v kině
- Millionaire game s media_type='movie'
"""

import xbmc
import xbmcgui
import xbmcaddon
import random
import threading
from urllib.parse import quote_plus

from wcs.ai.DialogMyTV import MyTVDialog
from wcs.ai.MediaChannelManager import MediaChannelManager
from wcs.ai.DialogAddMedia import AddMediaDialog, create_add_media_controller
from wcs.ai import ChannelHistory
from wcs.caching import get_cache_manager


class MyCinemaDialog(MyTVDialog):
    """
    Dialog pro MyCinema - správa filmových kin.
    
    Dědí z MyTVDialog a přepisuje metody specifické pro filmy.
    Používá sdílený Apple TV XML layout řízený Python properties.
    """
    
    def __init__(self, xml_filename, addon_path, *args, **kwargs):
        # Override channel type before calling parent __init__
        self._channel_type = 'cinema'
        super(MyCinemaDialog, self).__init__(xml_filename, addon_path, *args, **kwargs)
        
        # Override with cinema channel manager
        self.channel_manager = MediaChannelManager(self.addon, channel_type='cinema')
        
        # Nav section for sidebar
        self._nav_section_id = 'my_cinema'
    
    def onInit(self):
        """Initialize dialog with cinema-specific settings."""
        self._reset_state()
        
        # Cinema-specific title
        self.setProperty('WCS.AIChat.Title', 'MyCinema')
        self.setProperty('WCS.AIChat.Status', 'Pripraveno')
        
        # Set media type property for XML conditional visibility
        self.setProperty('WCS.MediaType', 'cinema')
        
        # Cinema-specific button labels
        self.setProperty('WCS.Button.Play', 'Prehrat filmy')
        self.setProperty('WCS.Button.PlayEp', 'Prehrat film')
        self.setProperty('WCS.Button.PlaySeries', 'Prehrat film')  # Fallback (hidden in cinema)
        self.setProperty('WCS.Button.Delete', 'Smazat kino')
        self.setProperty('WCS.Button.DeleteConfirm', 'Opravdu smazat kino?')
        
        # Cinema-specific row labels
        self.setProperty('WCS.Row1.Label', 'Moje kina')
        self.setProperty('WCS.Row3.Label', 'Moje filmy')
        
        # Open the cinema selected by the originating widget.
        self.current_channel_index = 0
        if self._initial_channel_id:
            for index, channel in enumerate(self.channel_manager.get_all_channels()):
                if channel.id == self._initial_channel_id:
                    self.current_channel_index = index
                    break
        
        # CLEAR ALL BACKGROUND PROPERTIES - Start fresh with matte layer
        self.clearProperty('WCS.MyTV.Background.Custom')
        self.clearProperty('WCS.MyTV.Background.Ready')
        
        # Clear any leftover confirmation dialogs from previous session
        self.clearProperty('WCS.MyTV.DeleteSeriesConfirm')
        self.clearProperty('WCS.MyTV.DeleteConfirm')
        
        # Clear hero zone
        self._clear_hero_zone()
        
        # RESET PROGRAM LIST IMMEDIATELY - Clear cached items
        try:
            program_list = self.getControl(9000)
            program_list.reset()
        except:
            pass
        
        # Set background mode and animation properties
        self._setup_background_properties()
        
        # Static mode: Only set Ready if no processing needed
        if self._bg_mode == self.BG_STATIC and not self._is_background_processing_needed():
            self.setProperty('WCS.MyTV.Background.Ready', 'true')
        
        # Poster collage: Start background generation IMMEDIATELY
        if self._bg_mode == self.BG_COLLAGE_POSTERS:
            self._update_background()
        
        # Static mode with effects: Generate blurred version
        if self._bg_mode == self.BG_STATIC and self._is_background_processing_needed():
            self._update_background()
        
        # Load View -- skip set_focus when no cinemas (Add dialog will manage focus)
        has_cinemas = bool(self.channel_manager.get_all_channels())
        self.refresh_channels_view(set_focus=has_cinemas and not self._initial_edit)
        
        # Populate My Movies list (ROW 3)
        self._populate_my_series_list()
        
        # Trigger background generation for other modes
        if self._bg_mode not in (self.BG_STATIC, self.BG_COLLAGE_POSTERS):
            self._update_background()
        
        # Ensure sidebar is hidden initially
        if self._show_nav_on_init:
            self._show_nav_sidebar(animate=False)
        else:
            self.clearProperty('WCS.AIChat.Visible')

        # Auto-open Add Media dialog when no cinemas exist
        if not has_cinemas:
            self._create_new_channel()
        elif self._initial_edit:
            self._show_series_grid_dialog()
    
    # ==================================================================================
    # OVERRIDE: HERO ZONE - Shows first movie from program list
    # ==================================================================================
    
    def _update_hero_zone(self):
        """Update hero zone properties from the first movie in program list."""
        try:
            program_list = self.getControl(9000)
            if program_list.size() == 0:
                self._clear_hero_zone()
                return
            
            item = program_list.getListItem(0)
            if not item:
                self._clear_hero_zone()
                return
            
            # Movie name
            movie_name = item.getLabel() or ''
            self.setProperty('WCS.MyTV.Hero.SeriesName', movie_name)
            
            # Fanart (backdrop)
            fanart = item.getArt('fanart') or item.getProperty('fanart') or ''
            self.setProperty('WCS.MyTV.Hero.Fanart', fanart)
            
            # Year as episode code
            year = item.getProperty('year') or ''
            self.setProperty('WCS.MyTV.Hero.EpCode', year)
            
            # Tagline as episode title
            ep_title = item.getProperty('episode_title') or ''
            self.setProperty('WCS.MyTV.Hero.EpTitle', ep_title)
            
            # Plot (max 300 chars)
            plot = item.getProperty('plot') or ''
            if len(plot) > 300:
                plot = plot[:297] + '...'
            self.setProperty('WCS.MyTV.Hero.Plot', plot)
            
            # Metadata line: genre | runtime | year | rating
            meta_parts = []
            # Genre from movie data
            genre = item.getProperty('genre') or ''
            if genre:
                meta_parts.append(genre)
            runtime = item.getLabel2() or ''
            if runtime:
                meta_parts.append(runtime)
            if year:
                meta_parts.append(year)
            rating = item.getProperty('rating') or ''
            if rating:
                meta_parts.append(f"★ {rating}")
            self.setProperty('WCS.MyTV.Hero.MetaLine', '  |  '.join(meta_parts))
            
            # Series logo (clearlogo of movie)
            logo = item.getProperty('series_logo') or ''
            self.setProperty('WCS.MyTV.Hero.SeriesLogo', logo)
            
            # Resume check
            channel_id = item.getProperty('channel_id') or ''
            movie_id = item.getProperty('movie_id') or ''
            if channel_id and movie_id:
                try:
                    resume = ChannelHistory.get_movie_resume_point(channel_id, movie_id)
                    if resume and resume.get('position', 0) > 60:
                        self.setProperty('WCS.MyTV.Hero.HasResume', 'true')
                        self.setProperty('WCS.Button.PlayEp', 'Pokracovat')
                    else:
                        self.clearProperty('WCS.MyTV.Hero.HasResume')
                        self.setProperty('WCS.Button.PlayEp', 'Prehrat film')
                except Exception:
                    self.clearProperty('WCS.MyTV.Hero.HasResume')
            else:
                self.clearProperty('WCS.MyTV.Hero.HasResume')
                
        except Exception as e:
            xbmc.log(f"[MyCinema] Error updating hero zone: {e}", xbmc.LOGERROR)
    
    # ==================================================================================
    # OVERRIDE: CHANNEL STATS - Cinema-specific labels
    # ==================================================================================
    
    def _update_channel_stats(self, channel_id):
        """Update channel statistics display for cinema."""
        channels = self.channel_manager.get_all_channels()
        total_channels = len(channels)
        total_movies = sum(len(ch.media_list) for ch in channels)
        
        self.setProperty('WCS.Channel.GlobalStats',
                         f"{total_channels} kin · {total_movies} filmů")
        
        # Current cinema name in title
        channel = self.channel_manager.get_channel_by_id(channel_id)
        if channel:
            self.setProperty('WCS.AIChat.Title', f"MyCinema · {channel.name}")
        else:
            self.setProperty('WCS.AIChat.Title', 'MyCinema')
    
    # ==================================================================================
    # OVERRIDE: MY MOVIES LIST (ROW 3) - Unique movies from all cinemas
    # ==================================================================================
    
    def _populate_my_series_list(self):
        """Populate My Movies list (9060) with unique movies from all cinemas + user_data."""
        try:
            my_movies_list = self.getControl(9060)
            my_movies_list.reset()
            
            seen_ids = set()
            all_movies = []
            
            # 1. Movies from user_data ("Moje filmy")
            try:
                from wcs import user_data
                saved_movies = user_data.load_tmdb_movies(self.addon) or []
                for movie in saved_movies:
                    movie_id = str(movie.get('id', '') or movie.get('tmdb_id', ''))
                    if movie_id and movie_id not in seen_ids:
                        seen_ids.add(movie_id)
                        all_movies.append(movie)
            except Exception as e:
                xbmc.log(f"[MyCinema] Error loading saved movies: {e}", xbmc.LOGWARNING)
            
            # 2. Movies from all cinemas
            channels = self.channel_manager.get_all_channels()
            for channel in channels:
                for movie in channel.media_list:
                    movie_id = str(movie.get('id', ''))
                    if movie_id and movie_id not in seen_ids:
                        seen_ids.add(movie_id)
                        all_movies.append(movie)
            
            # Populate list
            for movie in all_movies:
                name = movie.get('name') or movie.get('title', '')
                item = xbmcgui.ListItem(label=name)
                
                poster = movie.get('poster_path') or movie.get('poster')
                if poster and not poster.startswith('http'):
                    poster = f"https://image.tmdb.org/t/p/w500{poster}"
                elif not poster:
                    poster = 'special://home/addons/plugin.video.milionar/resources/media/placeholder_movie_card.png'
                
                movie_id = str(movie.get('id', '') or movie.get('tmdb_id', ''))
                item.setArt({'poster': poster})
                item.setProperty('series_id', movie_id)  # Reuse property name for parent compat
                item.setProperty('movie_id', movie_id)
                # Find channel_id for this movie (first match)
                ch_id = ''
                for ch in self.channel_manager.get_all_channels():
                    for m in ch.media_list:
                        if str(m.get('id', '')) == movie_id:
                            ch_id = ch.id
                            break
                    if ch_id:
                        break
                item.setProperty('channel_id', ch_id)
                my_movies_list.addItem(item)
            
            # Update Row3 label with count
            self.setProperty('WCS.Row3.Label', f"Moje filmy  \u00b7  {len(all_movies)}")
                        
        except Exception as e:
            xbmc.log(f"[MyCinema] Error populating My Movies list: {e}", xbmc.LOGERROR)
    
    # ==================================================================================
    # OVERRIDE: onClick - Cinema-specific handlers
    # ==================================================================================
    
    def onClick(self, controlId):
        """Handle clicks with cinema-specific logic."""
        # Delegate to Edit Progress dialog first if active (unlikely but safe)
        if self._handle_edit_progress_click(controlId):
            return
        
        # Delegate to Series Detail dialog first if active
        if self._handle_series_detail_click(controlId):
            return
        
        # Delegate to Add Series controller if active
        if self._handle_add_series_click(controlId):
            return
        
        if controlId == 2000:
            # Handle reorder mode confirmation
            if self.getProperty('WCS.MyTV.ReorderMode') == 'true':
                self._confirm_reorder()
                return
            
            # Check if "Create New"
            list_control = self.getControl(2000)
            item = list_control.getSelectedItem()
            if item.getProperty('is_create_button') == 'true':
                self._create_new_channel()
                return
            else:
                # Open series grid sub-dialog for this cinema
                self._show_series_grid_dialog()
                return
        
        elif controlId == 9100:
            # Grid item click (movie or add button)
            self._handle_grid_click()
        
        elif controlId == 9110:
            # Play all movies from Series Grid
            self._close_series_grid_dialog()
            self._play_broadcast()
        
        elif controlId == 9111:
            # Shuffle from Series Grid
            self.refresh_program_view()
            self._show_toast("Program zamícháno", "success")
        
        elif controlId == 9112:
            # Move Channel (reorder) from Series Grid
            self._enter_reorder_mode()
        
        elif controlId == 9113:
            # Regenerate Channel Name via AI from Series Grid
            self._regenerate_channel_name_from_grid()
        
        elif controlId == 9114:
            # Delete Channel from Series Grid
            self._show_delete_confirmation()
        
        elif controlId == 9115:
            # Milionář from Series Grid -- cinema mix mode
            self._play_game_from_cinema_grid()
        
        elif controlId == 9060:
            # My Movies list item clicked - open Movie Detail
            self._handle_my_movies_click()
        
        elif controlId == 9003:
            self._show_delete_confirmation()
        elif controlId == 9006:
            self._confirm_delete_channel()
        elif controlId == 9007:
            self._cancel_delete_confirmation()
        
        elif controlId == 9004:
            # Play all movies (broadcast)
            self._play_broadcast()
        
        elif controlId == 9040:
            # Play first movie from hero zone
            self._play_hero_movie()
        
        elif controlId == 9042:
            # Hero zone clicked - play first movie
            self._play_hero_movie()
        
        elif controlId == 9043:
            # Milionář from Home - movie mode for first movie in program
            self._play_game_from_home()
        
        elif controlId == 9000:
            # Program list item clicked - play movie
            if self.getProperty('WCS.MyTV.ProgramReorderMode') == 'true':
                self._confirm_program_reorder()
                return
            self._play_program_item()
        
        elif controlId == 9024:
            # Info box clicked - play movie
            self._play_program_item()
        
        # Parent handles remaining (sidebar etc.)
        super(MyTVDialog, self).onClick(controlId)
    
    # ==================================================================================
    # GAME: Milionář integration for movies
    # ==================================================================================
    
    def _play_game_from_home(self):
        """Start Millionaire game from Home button (9043) with first movie context."""
        try:
            program_list = self.getControl(9000)
            if program_list.size() == 0:
                self._show_toast("Žádné filmy v kině", "warning")
                return
            
            item = program_list.getListItem(0)
            if not item:
                return
            
            movie_name = item.getLabel() or ''
            plot = item.getProperty('plot') or ''
            poster = item.getArt('poster') or ''
            fanart = item.getArt('fanart') or ''
            logo = item.getProperty('series_logo') or ''
            movie_id = item.getProperty('movie_id') or ''
            
            self._show_game_dialog(
                series_id=movie_id,
                title=movie_name,
                plot=plot,
                poster=poster,
                fanart=fanart,
                logo=logo,
                media_type='movie'
            )
        except Exception as e:
            xbmc.log(f"[MyCinema] Error starting game from home: {e}", xbmc.LOGERROR)
    
    def _play_game_from_cinema_grid(self):
        """Start Millionaire game from Series Grid (9115) with cinema mix context."""
        try:
            list_control = self.getControl(2000)
            item = list_control.getSelectedItem()
            if not item:
                return
            
            channel_id = item.getProperty('channel_id')
            channel = self.channel_manager.get_channel_by_id(channel_id)
            if not channel or not channel.media_list:
                self._show_toast("Žádné filmy v kině", "warning")
                return
            
            cinema_name = channel.name or ''
            
            # Build combined plot from all movies
            movie_parts = []
            for m in channel.media_list:
                name = m.get('name') or m.get('title', '')
                overview = m.get('overview', '')
                if name:
                    if overview:
                        movie_parts.append(f'"{name}": {overview}')
                    else:
                        movie_parts.append(f'"{name}"')
            combined_plot = ' | '.join(movie_parts)
            
            # Use channel icon as poster
            poster = channel.icon or ''
            
            self._show_game_dialog(
                series_id='',
                title=cinema_name,
                plot=combined_plot,
                poster=poster,
                fanart='',
                logo='',
                media_type='channel'
            )
        except Exception as e:
            xbmc.log(f"[MyCinema] Error starting game from grid: {e}", xbmc.LOGERROR)
    
    # ==================================================================================
    # PLAY: Hero movie playback
    # ==================================================================================
    
    def _play_hero_movie(self):
        """Play the first movie from program list (hero zone)."""
        try:
            program_list = self.getControl(9000)
            if program_list.size() == 0:
                self._show_toast("Žádné filmy k přehrání", "warning")
                return
            
            # Select the first item so _play_program_item uses it
            program_list.selectItem(0)
            self._play_program_item()
        except Exception as e:
            xbmc.log(f"[MyCinema] Error playing hero movie: {e}", xbmc.LOGERROR)
    
    def _handle_my_movies_click(self):
        """Handle click on My Movies list (9060) - open movie detail."""
        try:
            my_movies_list = self.getControl(9060)
            selected = my_movies_list.getSelectedItem()
            if selected:
                movie_id = selected.getProperty('movie_id')
                channel_id = selected.getProperty('channel_id')
                if movie_id and channel_id:
                    self._show_movie_detail_dialog(movie_id, channel_id)
        except Exception as e:
            xbmc.log(f"[MyCinema] Error opening movie detail from My Movies: {e}", xbmc.LOGERROR)
    
    # ==================================================================================
    # OVERRIDE: ADD MEDIA DIALOG - Používá sdílený AddMediaDialog s media_type='cinema'
    # ==================================================================================
    
    def _show_add_series_dialog(self):
        """
        Override: Show the inline Add Media dialog for MOVIES.
        
        Toto je klíčová přepsaná metoda - parent volá tuto metodu pro grid,
        my ji přepisujeme aby používala media_type='cinema' místo 'tv'.
        """
        list_control = self.getControl(2000)
        channel_id = list_control.getSelectedItem().getProperty('channel_id')
        
        # Create controller using unified AddMediaDialog with media_type='cinema'
        self._add_series_controller = create_add_media_controller(
            self, self.addon, self.channel_manager, channel_id,
            on_close_callback=None,
            media_type='cinema'
        )
        
        # Show the inline dialog
        self._add_series_controller.show()
    
    def _close_add_series_dialog(self):
        """
        Override: Close the inline Add Media dialog and refresh if needed.
        Handles cinema-specific naming and channel creation logic.
        """
        if not hasattr(self, '_add_series_controller') or not self._add_series_controller:
            return
        
        media_added = self._add_series_controller.was_media_added()
        channel_id = self._add_series_controller.channel_id
        self._add_series_controller.hide()
        self._add_series_controller = None
        
        # Check if this was a newly created cinema that needs auto-naming
        pending_channel_id = getattr(self, '_pending_new_channel_id', None)
        
        if pending_channel_id and pending_channel_id == channel_id:
            self._pending_new_channel_id = None
            
            channel = self.channel_manager.get_channel_by_id(channel_id)
            
            if not channel or not channel.media_list:
                # No movies added - delete the empty cinema
                self.channel_manager.delete_channel(channel_id)
                self._show_toast("Kino nebylo vytvoreno - nepridali jste zadne filmy", "warning")
            else:
                # Generate cinema name based on genres
                from wcs.ai.ChannelNameGenerator import ChannelNameGenerator
                generator = ChannelNameGenerator(self.addon)
                
                naming_mode = self.addon.getSetting('mytv_channel_naming') or ''
                
                if 'AI' in naming_mode or naming_mode == '1':
                    # AI mode - use temporary name and generate asynchronously
                    temp_name = generator.generate_from_genres(channel.media_list, media_type='cinema')
                    self.channel_manager.rename_channel(channel_id, temp_name)
                    self.channel_manager.generate_channel_composite(channel_id)
                    self._generate_ai_channel_name_async(channel_id, channel.media_list, generator)
                else:
                    # Sync genre-based naming
                    new_name = generator.generate_from_genres(channel.media_list, media_type='cinema')
                    self.channel_manager.rename_channel(channel_id, new_name)
                    self.channel_manager.generate_channel_composite(channel_id)
                    self._show_toast(f"Kino '{new_name}' vytvoreno", "success")
            
            # Full refresh
            self.current_channel_index = 0
            self.refresh_channels_view(set_focus=True)
        
        elif media_added:
            # Just refresh the current channel
            self.channel_manager.generate_channel_composite(channel_id)
            self.update_editor_view()
            self.refresh_program_view()
            self.refresh_channels_view()
            self._populate_my_series_list()
    
    def _generate_ai_channel_name_async(self, channel_id, media_list, generator):
        """Generate AI name for cinema asynchronously."""
        def worker():
            try:
                ai_name = generator.generate_from_ai(media_list, media_type='cinema')
                if ai_name:
                    self.channel_manager.rename_channel(channel_id, ai_name)
                    self.refresh_channels_view()
                    self._show_toast(f"AI pojmenovalo kino: {ai_name}", "success")
            except Exception as e:
                xbmc.log(f"[MyCinema] AI naming error: {e}", xbmc.LOGERROR)
        
        threading.Thread(target=worker, daemon=True).start()
    
    # ==================================================================================
    # OVERRIDE: CHANNEL LIST VIEW - Cinema-specific labels and placeholders
    # ==================================================================================
    
    def refresh_channels_view(self, set_focus=False):
        """Populate the bottom list with cinema channels (kina)."""
        channels = self.channel_manager.get_all_channels()
        list_control = self.getControl(2000)
        list_control.reset()
        
        for ch in channels:
            item = xbmcgui.ListItem(label=ch.name)
            icon = ch.icon if ch.icon else 'special://home/addons/plugin.video.milionar/resources/media/placeholder_movie_card.png'
            item.setArt({'poster': icon})
            item.setProperty('channel_id', ch.id)
            list_control.addItem(item)
            
        # Add "Create New Cinema" item
        create_item = xbmcgui.ListItem(label="Vytvorit nove kino")
        create_item.setArt({'poster': 'special://home/addons/plugin.video.milionar/resources/media/plus_card.png'})
        create_item.setProperty('is_create_button', 'true')
        list_control.addItem(create_item)
            
        # Select first if available
        if self.current_channel_index >= list_control.size():
            self.current_channel_index = 0
            
        if list_control.size() > 0:
            list_control.selectItem(self.current_channel_index)
            if self._initial_channel_id and list_control.getSelectedPosition() != self.current_channel_index:
                xbmc.executebuiltin(f'SetFocus(2000,{self.current_channel_index},absolute)', True)
            self.update_editor_view()
            self.refresh_program_view()
            if set_focus:
                self._delayed_focus(2000, delay=0.5)
    
    # ==================================================================================
    # OVERRIDE: EDITOR GRID - Shows movies instead of series
    # ==================================================================================
    
    def update_editor_view(self):
        """Update grid 9100 based on selected cinema - shows movies."""
        list_control = self.getControl(2000)
        idx = list_control.getSelectedPosition()
        if idx < 0:
            return
            
        item = list_control.getListItem(idx)
        
        # If "Create New" is selected, clear editor and return
        if item.getProperty('is_create_button') == 'true':
            self.getControl(9100).reset()
            return
            
        channel_id = item.getProperty('channel_id')
        channel = self.channel_manager.get_channel_by_id(channel_id)
        
        grid_control = self.getControl(9100)
        grid_control.reset()
        
        if channel:
            # Add existing movies
            for movie in channel.media_list:
                m_item = xbmcgui.ListItem(label=movie.get('name') or movie.get('title', ''))
                poster = movie.get('poster_path') or movie.get('poster')
                if poster and not poster.startswith('http'):
                     poster = f"https://image.tmdb.org/t/p/w500{poster}"
                elif not poster:
                     poster = 'special://home/addons/plugin.video.milionar/resources/media/placeholder_movie_card.png'
                
                m_item.setArt({'poster': poster})
                m_item.setProperty('movie_id', str(movie.get('id')))
                m_item.setProperty('channel_id', channel_id)
                grid_control.addItem(m_item)

            # Always add "Add Movie" card at the end of the grid
            add_item = xbmcgui.ListItem(label="Pridat film")
            add_item.setArt({'poster': 'special://home/addons/plugin.video.milionar/resources/media/plus_card.png'})
            add_item.setProperty('is_add_button', 'true')
            add_item.setProperty('channel_id', channel_id)
            grid_control.addItem(add_item)
    
    # ==================================================================================
    # OVERRIDE: PROGRAM VIEW - Shows movie list (simplified, no episodes)
    # ==================================================================================
    
    def refresh_program_view(self, shuffle=False):
        """Load movie list for the current cinema (simplified - no episodes)."""
        # Initialize state if needed
        if not hasattr(self, '_program_load_token'):
            self._program_load_token = 0
        if not hasattr(self, '_program_load_timer'):
            self._program_load_timer = None
        
        # Increment token
        self._program_load_token += 1
        current_token = self._program_load_token
        
        # Get channel ID
        list_control = self.getControl(2000)
        idx = list_control.getSelectedPosition()
        if idx < 0:
            return
        
        item = list_control.getListItem(idx)
        channel_id = item.getProperty('channel_id')
        if not channel_id:
            return
        
        self._current_loaded_channel_id = channel_id
        
        # Update channel statistics display
        self._update_channel_stats(channel_id)
        
        # Cancel existing timer
        if self._program_load_timer:
            self._program_load_timer.cancel()
        
        # Schedule debounced async refresh
        self._program_load_timer = threading.Timer(
            0.3,
            self._async_movie_load,
            args=(current_token, channel_id)
        )
        self._program_load_timer.daemon = True
        self._program_load_timer.start()
    
    def _async_movie_load(self, token, channel_id):
        """Load movies for the program list (async worker)."""
        # Check if still valid
        if token != self._program_load_token:
            return
        
        channel = self.channel_manager.get_channel_by_id(channel_id)
        if not channel or not channel.media_list:
            try:
                program_list = self.getControl(9000)
                program_list.reset()
                self._clear_hero_zone()
            except:
                pass
            return
        
        # Shuffle movies
        movies = list(channel.media_list)
        random.shuffle(movies)
        
        # Update UI on main thread
        try:
            program_list = self.getControl(9000)
            program_list.reset()
            
            for movie in movies[:20]:  # Limit to 20 movies
                item = self._create_movie_list_item(movie, channel_id)
                if item:
                    program_list.addItem(item)
            
            # Update hero zone with first movie
            self._update_hero_zone()
            
            # Update background
            self._update_background(channel_id=channel_id)
            
        except Exception as e:
            xbmc.log(f"[MyCinema] Error loading movies: {e}", xbmc.LOGERROR)
    
    def _create_movie_list_item(self, movie, channel_id):
        """Create ListItem for movie in program list."""
        try:
            name = movie.get('name') or movie.get('title', 'Neznamy film')
            item = xbmcgui.ListItem(label=name)
            
            # Poster/thumb
            poster = movie.get('poster_path') or movie.get('poster')
            if poster and not poster.startswith('http'):
                poster = f"https://image.tmdb.org/t/p/w500{poster}"
            
            backdrop = movie.get('backdrop_path') or movie.get('fanart')
            if backdrop and not backdrop.startswith('http'):
                backdrop = f"https://image.tmdb.org/t/p/w1280{backdrop}"
            
            item.setArt({
                'poster': poster or 'special://home/addons/plugin.video.milionar/resources/media/placeholder_movie_card.png',
                'thumb': backdrop or poster or '',
                'fanart': backdrop or ''
            })
            
            # Properties
            year = movie.get('release_date', '')[:4] if movie.get('release_date') else ''
            runtime = movie.get('runtime', 0)
            if runtime:
                item.setLabel2(f"{runtime} min")
            
            item.setProperty('movie_id', str(movie.get('id', '')))
            item.setProperty('channel_id', channel_id)
            item.setProperty('year', year)
            item.setProperty('plot', movie.get('overview', ''))
            item.setProperty('plot_short', (movie.get('overview', '')[:100] + '...') if len(movie.get('overview', '')) > 100 else movie.get('overview', ''))
            item.setProperty('genre', movie.get('genre', ''))
            item.setProperty('rating', str(movie.get('vote_average', '')) if movie.get('vote_average') else '')
            
            # For UI compatibility with TV layout
            # Use tagline if available, otherwise empty
            item.setProperty('episode_title', movie.get('tagline', ''))
            item.setProperty('ep_code', year)
            
            # Check if movie was watched
            movie_id = movie.get('id')
            if movie_id and channel_id:
                if ChannelHistory.is_movie_watched(channel_id, movie_id):
                    item.setProperty('watched', 'true')
            
            return item
        except Exception as e:
            xbmc.log(f"[MyCinema] Error creating movie item: {e}", xbmc.LOGERROR)
            return None
    
    # ==================================================================================
    # OVERRIDE: GRID CLICK - Handle movie cards (uses movie_id instead of series_id)
    # ==================================================================================
    
    def _handle_grid_click(self):
        """Handle click on grid items - movies or add button."""
        self._block_sidebar = True
        try:
            grid = self.getControl(9100)
            item = grid.getSelectedItem()
            if not item:
                return
            
            # Check if it's the "Add Movie" placeholder
            if item.getProperty('is_add_button') == 'true':
                # Show Add Media dialog for movies
                self._show_add_series_dialog()  # Uses our override with media_type='cinema'
                return

            # Show Movie Detail dialog (reusing the Series Detail UI)
            movie_id = item.getProperty('movie_id')
            channel_id = item.getProperty('channel_id')
            self._show_movie_detail_dialog(movie_id, channel_id)
        finally:
            self._block_sidebar = False
    
    def _show_movie_detail_dialog(self, movie_id, channel_id):
        """Show the inline Movie Detail dialog (reuses Series Detail UI)."""
        # Store current movie info for removal action
        self._series_detail_series_id = movie_id  # Reuse same property name for removal
        self._series_detail_channel_id = channel_id
        
        # Get movie data from channel
        channel = self.channel_manager.get_channel_by_id(channel_id)
        movie_data = None
        if channel:
            for m in channel.media_list:
                if str(m.get('id')) == str(movie_id):
                    movie_data = m
                    break
        
        if not movie_data:
            xbmc.log(f"[MyCinema] Movie data not found for id={movie_id}", xbmc.LOGWARNING)
            return
        
        # Fetch additional metadata from TMDb
        metadata = self._get_movie_metadata(movie_id, movie_data)
        
        # Set window properties for XML (using same SeriesDetail properties)
        self.setProperty('WCS.MyTV.SeriesDetail.Name', metadata.get('name', ''))
        self.setProperty('WCS.MyTV.SeriesDetail.Year', str(metadata.get('year', '')))
        self.setProperty('WCS.MyTV.SeriesDetail.Genre', metadata.get('genre', ''))
        self.setProperty('WCS.MyTV.SeriesDetail.Rating', str(metadata.get('rating', '')))
        self.setProperty('WCS.MyTV.SeriesDetail.Plot', metadata.get('plot', ''))
        self.setProperty('WCS.MyTV.SeriesDetail.Fanart', metadata.get('fanart', ''))
        self.setProperty('WCS.MyTV.SeriesDetail.Logo', metadata.get('logo', ''))
        self.setProperty('WCS.MyTV.SeriesDetail.Poster', metadata.get('poster', ''))
        
        # Show the dialog
        self.setProperty('WCS.MyTV.SeriesDetail.Active', 'true')
        
        # Focus on remove button
        self._delayed_focus(9300, delay=0.1)
    
    def _get_movie_metadata(self, movie_id, movie_data):
        """Get movie metadata from cache or TMDb."""
        import requests
        from wcs.metadata.TMDbClient import get_tmdb_api_key
        
        # Try cache first - only use if it has meaningful data
        cache_key = f"movie_detail_{movie_id}"
        cached = self._cache.get(cache_key)
        if cached and (cached.get('fanart') or cached.get('genre') or cached.get('rating')):
            return cached
        
        # Build basic metadata from what we have
        metadata = {
            'name': movie_data.get('name') or movie_data.get('title', ''),
            'year': movie_data.get('year', '') or (movie_data.get('release_date', '')[:4] if movie_data.get('release_date') else ''),
            'genre': '',
            'rating': '',
            'plot': movie_data.get('overview', '') or movie_data.get('plot', ''),
            'fanart': '',
            'logo': '',
            'poster': ''
        }
        
        # Get poster
        poster = movie_data.get('poster_path') or movie_data.get('poster')
        if poster:
            if not poster.startswith('http'):
                poster = f"https://image.tmdb.org/t/p/w500{poster}"
            metadata['poster'] = poster
        
        # Fetch full details from TMDb
        try:
            api_key = get_tmdb_api_key(self.addon)
            
            # Fetch movie details
            details_url = f'https://api.themoviedb.org/3/movie/{movie_id}?api_key={api_key}&language=cs-CZ'
            response = requests.get(details_url, timeout=10)
            if response.status_code == 200:
                details = response.json()
                
                metadata['name'] = details.get('title', metadata['name'])
                metadata['plot'] = details.get('overview', metadata['plot'])
                metadata['rating'] = f"{details.get('vote_average', 0):.1f}"
                
                # Year
                if details.get('release_date'):
                    metadata['year'] = details['release_date'][:4]
                
                # Genres
                genres = details.get('genres', [])
                if genres:
                    metadata['genre'] = ', '.join([g.get('name', '') for g in genres[:3]])
                
                # Fanart/backdrop
                backdrop = details.get('backdrop_path')
                if backdrop:
                    metadata['fanart'] = f"https://image.tmdb.org/t/p/w1280{backdrop}"
            else:
                xbmc.log(f"[MyCinema] TMDb API error for movie {movie_id}: {response.status_code}", xbmc.LOGWARNING)
            
            # Fetch images for clearlogo
            images_url = f'https://api.themoviedb.org/3/movie/{movie_id}/images?api_key={api_key}'
            response = requests.get(images_url, timeout=10)
            if response.status_code == 200:
                images = response.json()
                logos = images.get('logos', [])
                # Prefer Czech or English logo
                for logo in logos:
                    if logo.get('iso_639_1') in ('cs', 'en', None):
                        logo_path = logo.get('file_path')
                        if logo_path:
                            metadata['logo'] = f"https://image.tmdb.org/t/p/w500{logo_path}"
                            break
            
            # Cache the result
            self._cache.set(cache_key, metadata, ttl_seconds=24*3600)
            
        except Exception as e:
            xbmc.log(f"[MyCinema] Error fetching movie metadata: {e}", xbmc.LOGWARNING)
        
        return metadata
    
    # ==================================================================================
    # OVERRIDE: NEW CHANNEL CREATION - Cinema-specific labels
    # ==================================================================================
    
    def _create_new_channel(self):
        """Create a new cinema with automatic naming based on added movies."""
        self._block_sidebar = True
        
        # Create channel with temporary name
        temp_name = f"Nove kino {len(self.channel_manager.channels) + 1}"
        new_channel = self.channel_manager.create_channel(temp_name)
        
        # Store the new channel ID for auto-naming after dialog closes
        self._pending_new_channel_id = new_channel.id
        
        # Select the new channel (first one - new channels are prepended)
        self.current_channel_index = 0
        
        # Only refresh channel list - NO program refresh needed for empty channel
        list_control = self.getControl(2000)
        list_control.reset()
        for ch in self.channel_manager.get_all_channels():
            item = xbmcgui.ListItem(label=ch.name)
            icon = ch.icon if ch.icon else 'special://home/addons/plugin.video.milionar/resources/media/placeholder_movie_card.png'
            item.setArt({'poster': icon})
            item.setProperty('channel_id', ch.id)
            list_control.addItem(item)
        
        # Add "Create New Cinema" item
        create_item = xbmcgui.ListItem(label="Vytvorit nove kino")
        create_item.setArt({'poster': 'special://home/addons/plugin.video.milionar/resources/media/plus_card.png'})
        create_item.setProperty('is_create_button', 'true')
        list_control.addItem(create_item)
        
        # Clear editor grid (empty channel)
        self.getControl(9100).reset()
        
        # Try to move focus  
        self.setFocusId(9100)
        xbmc.sleep(50)
        
        # Unblock sidebar before showing dialog
        self._block_sidebar = False
        
        # Open AddMediaDialog for movies
        self._show_add_series_dialog()  # Uses our override with media_type='cinema'
    
    # ==================================================================================
    # OVERRIDE: PROGRAM REORDER - Works with channel.media_list instead of cache
    # ==================================================================================
    
    def _confirm_program_reorder(self):
        """Confirm program reorder -- move movie to current cursor position.
        
        Parent uses cache (program_list_{channel_id}) which MyCinema doesn't populate.
        This override works directly with channel.media_list and persists the order.
        """
        original_index = getattr(self, '_program_reorder_original_index', None)
        if original_index is None:
            self._exit_program_reorder_mode(confirm=False)
            return
        
        program_list = self.getControl(9000)
        target_pos = program_list.getSelectedPosition()
        
        if target_pos < 0 or target_pos == original_index:
            self._exit_program_reorder_mode(confirm=False)
            return
        
        # Get current channel
        list_control = self.getControl(2000)
        channel_item = list_control.getSelectedItem()
        channel_id = channel_item.getProperty('channel_id') if channel_item else None
        
        if not channel_id:
            self._exit_program_reorder_mode(confirm=False)
            return
        
        channel = self.channel_manager.get_channel_by_id(channel_id)
        if not channel or not channel.media_list:
            self._exit_program_reorder_mode(confirm=False)
            return
        
        media_list = channel.media_list
        
        # Map program list indices to media_list indices
        # Program list may be shuffled/limited, so we need to map by movie_id
        program_size = program_list.size()
        program_movie_ids = []
        for i in range(program_size):
            item = program_list.getListItem(i)
            program_movie_ids.append(item.getProperty('movie_id'))
        
        # Get the movie_id being moved
        if original_index >= len(program_movie_ids):
            self._exit_program_reorder_mode(confirm=False)
            return
        
        moved_movie_id = program_movie_ids[original_index]
        
        # Find the movie in media_list and reorder
        moved_movie = None
        moved_idx = None
        for idx, m in enumerate(media_list):
            if str(m.get('id', '')) == moved_movie_id:
                moved_movie = m
                moved_idx = idx
                break
        
        if moved_movie is None:
            self._exit_program_reorder_mode(confirm=False)
            return
        
        # Find target movie_id and its position in media_list
        target_movie_id = program_movie_ids[target_pos]
        target_idx = None
        for idx, m in enumerate(media_list):
            if str(m.get('id', '')) == target_movie_id:
                target_idx = idx
                break
        
        if target_idx is None:
            self._exit_program_reorder_mode(confirm=False)
            return
        
        # Remove from original position and insert at target
        media_list.pop(moved_idx)
        # Adjust target index if needed (after removal)
        if moved_idx < target_idx:
            target_idx -= 1
        media_list.insert(target_idx, moved_movie)
        
        # Persist the change
        self.channel_manager._save_channels()
        
        # Reload program list (without shuffle to preserve new order)
        self._reload_program_list_ordered(channel_id)
        
        # Re-select the moved item at its new position
        program_list.selectItem(target_pos)
        
        xbmc.log(f"[MyCinema] Moved movie from {original_index} to {target_pos} in cinema {channel_id}", xbmc.LOGINFO)
        
        self._exit_program_reorder_mode(confirm=True)
    
    def _reload_program_list_ordered(self, channel_id):
        """Reload program list preserving current media_list order (no shuffle)."""
        channel = self.channel_manager.get_channel_by_id(channel_id)
        if not channel or not channel.media_list:
            return
        
        try:
            program_list = self.getControl(9000)
            program_list.reset()
            
            for movie in channel.media_list[:20]:
                item = self._create_movie_list_item(movie, channel_id)
                if item:
                    program_list.addItem(item)
            
            self._update_hero_zone()
        except Exception as e:
            xbmc.log(f"[MyCinema] Error reloading program list: {e}", xbmc.LOGERROR)
    
    # ==================================================================================
    # OVERRIDE: PLAY BROADCAST - Play random movie from cinema
    # ==================================================================================
    
    def _play_broadcast(self):
        """Plays all movies in the program list as a continuous playlist."""
        list_control = self.getControl(9000)
        size = list_control.size()
        if size == 0:
            self._show_toast("Zadne filmy k prehrani", "warning")
            return
            
        self.close()
        
        # Get Playlist
        playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
        playlist.clear()
        
        # Get current channel ID for history tracking
        channel_list = self.getControl(2000)
        current_channel_item = channel_list.getSelectedItem()
        channel_id = current_channel_item.getProperty('channel_id') if current_channel_item else ''
        
        # Add all movies to playlist
        for i in range(size):
            item = list_control.getListItem(i)
            
            movie_id = item.getProperty('movie_id')
            movie_name = item.getLabel()
            
            if not movie_id or not movie_name:
                continue

            # Metadata params
            plot = item.getProperty('plot') or ''
            year = item.getProperty('year') or ''
            poster = item.getArt('poster') or ''
            fanart = item.getArt('fanart') or ''
            
            # Construct plugin URL for movie playback
            url = (f"plugin://{self.addon.getAddonInfo('id')}?action=play_movie_from_addon_playlist"
                   f"&movie_name={quote_plus(movie_name)}"
                   f"&tmdb_id={movie_id}"
                   f"&plot={quote_plus(plot)}"
                   f"&poster={quote_plus(poster)}"
                   f"&fanart={quote_plus(fanart)}"
                   f"&year={quote_plus(year)}"
                   f"&mycinema_channel_id={quote_plus(channel_id)}")
            
            # Create list item for playlist
            li = xbmcgui.ListItem(label=movie_name)
            li.setInfo('video', {
                'title': movie_name,
                'plot': plot, 
                'year': int(year) if year.isdigit() else 0,
                'mediatype': 'movie'
            })
            li.setArt({
                'poster': poster,
                'fanart': fanart,
                'thumb': poster
            })
            
            playlist.add(url, li)
            
        # Start playback
        xbmc.Player().play(playlist)
    
    # ==================================================================================
    # OVERRIDE: DELETE CHANNEL - Cinema-specific toast message
    # ==================================================================================
    
    def _confirm_delete_channel(self):
        """Delete the cinema after confirmation (cinema-specific toast)."""
        channel_id = getattr(self, '_pending_delete_channel_id', None)
        if not channel_id:
            return
        
        # Hide confirmation dialog
        self.clearProperty('WCS.MyTV.DeleteConfirm')
        
        # Close grid if open (appletv layout)
        if self.getProperty('WCS.MyTV.SeriesGrid') == 'true':
            self.clearProperty('WCS.MyTV.SeriesGrid')
            self.clearProperty('WCS.MyTV.SeriesGrid.Title')
        
        # Delete channel and its history
        ChannelHistory.delete_channel_history(channel_id)
        self.channel_manager.delete_channel(channel_id)
        
        # Clear pending data
        self._pending_delete_channel_id = None
        self._pending_delete_channel_name = None
        
        # Refresh
        self.current_channel_index = 0
        self.refresh_channels_view()
        self._populate_my_series_list()
        
        # Focus on first channel
        self._delayed_focus(2000, delay=0.1)
        
        self._show_toast("Kino smazano", "success")
    
    def _play_program_item(self):
        """Play selected movie from program list."""
        try:
            program_list = self.getControl(9000)
            item = program_list.getSelectedItem()
            if not item:
                return
            
            movie_id = item.getProperty('movie_id')
            channel_id = item.getProperty('channel_id')
            movie_name = item.getLabel()
            
            if not movie_id:
                return
            
            # Mark as watched (correct arg order: channel_id, movie_id)
            ChannelHistory.mark_movie_watched(channel_id, movie_id)
            
            # Get metadata from item
            year = item.getProperty('year') or ''
            plot = item.getProperty('plot') or ''
            poster = item.getArt('poster') or ''
            fanart = item.getArt('fanart') or ''
            
            # Close dialog first
            self.close()
            
            # Play movie using the standard play function
            from wcs.utils import play_movie_from_addon
            meta = {
                'title': movie_name,
                'year': year,
                'plot': plot,
                'poster': poster,
                'fanart': fanart,
                'tmdb_id': movie_id,
                'mycinema_channel_id': channel_id
            }
            play_movie_from_addon(meta, self.addon)
            
        except Exception as e:
            xbmc.log(f"[MyCinema] Error playing movie: {e}", xbmc.LOGERROR)


def show_my_cinema_dialog(addon, show_nav_sidebar=False, nav_position=0, channel_id=None, context_uid='', context_row='', edit=False):
    """Factory function to show MyCinema dialog."""
    # Use same design setting as MyTV
    design = addon.getSetting('mytv_design') or '1'
    design_map = {
        '0': 'ai/DialogMyTV_classic.xml',
        '1': 'ai/DialogMyTV.xml',
        '2': 'ai/DialogMyTV_appletv.xml',
        '3': 'ai/DialogMyTV_kodi.xml',
    }
    xml_file = design_map.get(design, 'ai/DialogMyTV.xml')
    
    dialog = MyCinemaDialog(
        xml_file,
        addon.getAddonInfo('path'),
        "Default",
        "1080i",
        show_nav_sidebar=show_nav_sidebar,
        nav_position=nav_position,
        initial_channel_id=channel_id,
        context_uid=context_uid,
        context_row=context_row,
        initial_edit=edit
    )
    dialog.doModal()
    del dialog
