"""
PyQt6 Multi-threaded Video Player with QWebEngineView Overlay System
"""

import sys
import time
import logging
import json
from pathlib import Path
from typing import Optional, Dict, Any, List
from PyQt6.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QLabel, QPushButton, QSlider, QFrame, QStackedWidget
)
from PyQt6.QtCore import (
    Qt, QTimer, QThread, pyqtSignal, QUrl, QRect, QPropertyAnimation,
    QEasingCurve, QSequentialAnimationGroup, QObject, QMutex, QMutexLocker,
    QThreadPool, QRunnable, pyqtSlot
)
from PyQt6.QtGui import (
    QFont, QPainter, QPen, QBrush, QColor, QPixmap, QMovie, 
    QLinearGradient, QFontMetrics, QAction
)
from PyQt6.QtMultimedia import QMediaPlayer, QAudioOutput
from PyQt6.QtMultimediaWidgets import QVideoWidget
from PyQt6.QtWebEngineWidgets import QWebEngineView
from PyQt6.QtWebEngineCore import QWebEngineProfile
from PyQt6.QtWebChannel import QWebChannel

from ..core.thread_manager import ThreadedComponent
from ..core.message_bus import MessageBus, Message, MessageType, MessageBuilder
from ..config.settings import QtConfig
from .overlay_url_handler import OverlayUrlSchemeHandler

logger = logging.getLogger(__name__)


class OverlayWebChannel(QObject):
    """QObject for WebChannel communication with overlay HTML/JS"""
    
    # Signals to send data to JavaScript
    dataUpdated = pyqtSignal(dict)
    positionChanged = pyqtSignal(float, float)  # position, duration in seconds
    videoInfoChanged = pyqtSignal(dict)
    
    def __init__(self):
        super().__init__()
        self.mutex = QMutex()
        self.overlay_data = {}
        logger.info("OverlayWebChannel initialized")
    
    @pyqtSlot(str)
    def updateTitle(self, title: str):
        """Update main title from JavaScript"""
        with QMutexLocker(self.mutex):
            self.overlay_data['title'] = title
            self.dataUpdated.emit({'title': title})
            logger.debug(f"Title updated: {title}")
    
    @pyqtSlot(str)
    def updateSubtitle(self, subtitle: str):
        """Update subtitle from JavaScript"""
        with QMutexLocker(self.mutex):
            self.overlay_data['subtitle'] = subtitle
            self.dataUpdated.emit({'subtitle': subtitle})
            logger.debug(f"Subtitle updated: {subtitle}")
    
    @pyqtSlot(bool)
    def toggleStats(self, show: bool):
        """Toggle stats panel visibility"""
        with QMutexLocker(self.mutex):
            self.overlay_data['showStats'] = show
            self.dataUpdated.emit({'showStats': show})
            logger.debug(f"Stats panel toggled: {show}")
    
    def send_data_update(self, data: Dict[str, Any]):
        """Send data update to JavaScript (thread-safe)"""
        with QMutexLocker(self.mutex):
            self.overlay_data.update(data)
            self.dataUpdated.emit(data)
    
    def send_position_update(self, position: float, duration: float):
        """Send playback position update to JavaScript (thread-safe)"""
        self.positionChanged.emit(position, duration)
    
    def send_video_info(self, info: Dict[str, Any]):
        """Send video information to JavaScript (thread-safe)"""
        self.videoInfoChanged.emit(info)


class VideoProcessingWorker(QRunnable):
    """Background worker for video processing tasks"""
    
    def __init__(self, task_type: str, data: Dict[str, Any], callback=None):
        super().__init__()
        self.task_type = task_type
        self.data = data
        self.callback = callback
        self.setAutoDelete(True)
    
    def run(self):
        """Execute the video processing task"""
        try:
            logger.debug(f"Processing video task: {self.task_type}")
            
            if self.task_type == "metadata_extraction":
                result = self._extract_metadata()
            elif self.task_type == "thumbnail_generation":
                result = self._generate_thumbnail()
            elif self.task_type == "overlay_rendering":
                result = self._render_overlay()
            else:
                result = {"error": f"Unknown task type: {self.task_type}"}
            
            if self.callback:
                self.callback(result)
                
        except Exception as e:
            logger.error(f"Video processing worker error: {e}")
            if self.callback:
                self.callback({"error": str(e)})
    
    def _extract_metadata(self) -> Dict[str, Any]:
        """Extract video metadata"""
        # Placeholder for metadata extraction
        return {
            "resolution": "1920x1080",
            "bitrate": "5.2 Mbps",
            "codec": "H.264",
            "fps": "30.0"
        }
    
    def _generate_thumbnail(self) -> Dict[str, Any]:
        """Generate video thumbnail"""
        # Placeholder for thumbnail generation
        return {"thumbnail_path": "/tmp/thumbnail.jpg"}
    
    def _render_overlay(self) -> Dict[str, Any]:
        """Render overlay elements"""
        # Placeholder for overlay rendering
        return {"rendered": True}


class OverlayWebView(QWebEngineView):
    """Custom QWebEngineView for video overlays with transparent background"""
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.web_channel = None
        self.overlay_channel = None
        self.current_template = "default.html"
        
        # Built-in templates directory (bundled with app)
        self.builtin_templates_dir = Path(__file__).parent / "templates"
        
        # Persistent uploaded templates directory (user data)
        self.uploaded_templates_dir = self._get_persistent_templates_dir()
        self.uploaded_templates_dir.mkdir(parents=True, exist_ok=True)
        
        # Primary templates directory for backwards compatibility
        self.templates_dir = self.builtin_templates_dir
        
        self.setup_web_view()
        self._setup_custom_scheme()
        logger.info(f"OverlayWebView initialized - builtin: {self.builtin_templates_dir}, uploaded: {self.uploaded_templates_dir}")
    
    def setup_web_view(self):
        """Setup web view for transparent overlays"""
        # Enable transparency
        self.setAttribute(Qt.WidgetAttribute.WA_TranslucentBackground, True)
        self.setAttribute(Qt.WidgetAttribute.WA_TransparentForMouseEvents, True)
        
        # Configure page settings
        page = self.page()
        page.setBackgroundColor(QColor(0, 0, 0, 0))  # Transparent background
        
        # Setup WebChannel
        self.web_channel = QWebChannel()
        self.overlay_channel = OverlayWebChannel()
        self.web_channel.registerObject("overlay", self.overlay_channel)
        page.setWebChannel(self.web_channel)
        
        # Load default template
        self.load_template(self.current_template)
    
    def _setup_custom_scheme(self):
        """Setup custom URL scheme handler for overlay resources"""
        try:
            # Get the page's profile
            profile = self.page().profile()
            
            # Create and install URL scheme handler
            self.scheme_handler = OverlayUrlSchemeHandler(self)
            profile.installUrlSchemeHandler(b"overlay", self.scheme_handler)
            
            logger.info("Custom overlay:// URL scheme handler installed successfully")
            
        except Exception as e:
            logger.error(f"Failed to setup custom URL scheme: {e}")
    
    def load_template(self, template_name: str):
        """Load a specific template file, prioritizing uploaded templates"""
        try:
            # If no template name provided, use default
            if not template_name:
                template_name = "default.html"
            
            # Ensure .html extension
            if not template_name.endswith('.html'):
                template_name += '.html'
            
            # First try uploaded templates directory (user uploads take priority)
            template_path = self.uploaded_templates_dir / template_name
            template_source = "uploaded"
            
            # If not found in uploaded, try built-in templates
            if not template_path.exists():
                template_path = self.builtin_templates_dir / template_name
                template_source = "builtin"
            
            # If still not found, fallback to default.html in built-in templates
            if not template_path.exists():
                default_template_path = self.builtin_templates_dir / "default.html"
                if default_template_path.exists():
                    template_path = default_template_path
                    template_name = "default.html"
                    template_source = "builtin"
                    logger.warning(f"Template {template_name} not found, using default.html")
                else:
                    logger.error(f"No template found: {template_name}, and default.html missing")
                    return
            
            if template_path.exists():
                self.load(QUrl.fromLocalFile(str(template_path)))
                self.current_template = template_name
                logger.info(f"Loaded template: {template_path} (source: {template_source})")
            else:
                logger.error(f"No template found: {template_name}")
                
        except Exception as e:
            logger.error(f"Failed to load template {template_name}: {e}")
    
    def reload_current_template(self):
        """Reload the current template"""
        self.load_template(self.current_template)
    
    def get_available_templates(self) -> List[str]:
        """Get list of available template files from both directories"""
        try:
            templates = set()
            
            # Get built-in templates
            if self.builtin_templates_dir.exists():
                builtin_templates = [f.name for f in self.builtin_templates_dir.glob("*.html")]
                templates.update(builtin_templates)
            
            # Get uploaded templates (these override built-in ones with same name)
            if self.uploaded_templates_dir.exists():
                uploaded_templates = [f.name for f in self.uploaded_templates_dir.glob("*.html")]
                templates.update(uploaded_templates)
            
            template_list = sorted(list(templates))
            if not template_list:
                template_list = ["default.html"]
            
            return template_list
            
        except Exception as e:
            logger.error(f"Failed to get available templates: {e}")
            return ["default.html"]
    
    def _get_persistent_templates_dir(self) -> Path:
        """Get persistent templates directory for user uploads"""
        try:
            import platform
            import os
            
            system = platform.system()
            
            if system == "Windows":
                # Use AppData/Roaming on Windows
                app_data = os.getenv('APPDATA', os.path.expanduser('~'))
                templates_dir = Path(app_data) / "MbetterClient" / "templates"
            elif system == "Darwin":  # macOS
                # Use ~/Library/Application Support on macOS
                templates_dir = Path.home() / "Library" / "Application Support" / "MbetterClient" / "templates"
            else:  # Linux and other Unix-like systems
                # Use ~/.config on Linux
                config_home = os.getenv('XDG_CONFIG_HOME', str(Path.home() / ".config"))
                templates_dir = Path(config_home) / "MbetterClient" / "templates"
            
            logger.debug(f"Persistent templates directory: {templates_dir}")
            return templates_dir
                
        except Exception as e:
            logger.error(f"Failed to determine persistent templates directory: {e}")
            # Fallback to local directory
            return Path.cwd() / "user_templates"
    
    def get_overlay_channel(self) -> OverlayWebChannel:
        """Get the overlay communication channel"""
        return self.overlay_channel
    
    def update_overlay_data(self, data: Dict[str, Any]):
        """Update overlay with new data"""
        if self.overlay_channel:
            self.overlay_channel.send_data_update(data)
    
    def update_position(self, position: float, duration: float):
        """Update playback position"""
        if self.overlay_channel:
            self.overlay_channel.send_position_update(position, duration)
    
    def update_video_info(self, info: Dict[str, Any]):
        """Update video information"""
        if self.overlay_channel:
            self.overlay_channel.send_video_info(info)


class VideoWidget(QWidget):
    """Composite video widget with QWebEngineView overlay"""
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setup_ui()
        logger.info("VideoWidget initialized")
    
    def setup_ui(self):
        """Setup video widget with overlay"""
        self.setStyleSheet("background-color: black;")
        
        # Create layout
        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        
        # Create stacked widget for layering
        self.stacked_widget = QStackedWidget()
        
        # Create video widget for actual video playback
        self.video_widget = QVideoWidget()
        self.video_widget.setStyleSheet("background-color: black;")
        self.stacked_widget.addWidget(self.video_widget)
        
        # Create overlay web view
        self.overlay_view = OverlayWebView()
        self.stacked_widget.addWidget(self.overlay_view)
        
        layout.addWidget(self.stacked_widget)
        
        # Ensure overlay is on top by setting the current widget
        self.stacked_widget.setCurrentWidget(self.overlay_view)
    
    def get_video_widget(self) -> QVideoWidget:
        """Get the video widget for media player"""
        return self.video_widget
    
    def get_overlay_view(self) -> OverlayWebView:
        """Get the overlay web view"""
        return self.overlay_view
    
    def resizeEvent(self, event):
        """Handle resize events"""
        super().resizeEvent(event)
        # Both widgets should automatically resize with the stacked widget


class PlayerControlsWidget(QWidget):
    """Enhanced video player controls with thread-safe operations"""
    
    play_pause_clicked = pyqtSignal()
    stop_clicked = pyqtSignal()
    seek_requested = pyqtSignal(int)
    volume_changed = pyqtSignal(int)
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.mutex = QMutex()
        self.setup_ui()
    
    def setup_ui(self):
        """Setup enhanced control UI"""
        layout = QHBoxLayout(self)
        layout.setContentsMargins(10, 5, 10, 5)
        
        # Play/Pause button
        self.play_pause_btn = QPushButton("⏸️")
        self.play_pause_btn.setFixedSize(40, 30)
        self.play_pause_btn.clicked.connect(self.play_pause_clicked.emit)
        
        # Stop button
        self.stop_btn = QPushButton("⏹️")
        self.stop_btn.setFixedSize(40, 30)
        self.stop_btn.clicked.connect(self.stop_clicked.emit)
        
        # Position slider
        self.position_slider = QSlider(Qt.Orientation.Horizontal)
        self.position_slider.setMinimum(0)
        self.position_slider.setMaximum(100)
        self.position_slider.sliderPressed.connect(self._on_slider_pressed)
        self.position_slider.sliderReleased.connect(self._on_slider_released)
        
        # Volume slider
        self.volume_slider = QSlider(Qt.Orientation.Horizontal)
        self.volume_slider.setMinimum(0)
        self.volume_slider.setMaximum(100)
        self.volume_slider.setValue(100)
        self.volume_slider.setMaximumWidth(100)
        self.volume_slider.valueChanged.connect(self.volume_changed.emit)
        
        # Time labels
        self.current_time_label = QLabel("00:00")
        self.duration_label = QLabel("00:00")
        
        # Volume label
        volume_label = QLabel("🔊")
        
        # Layout
        layout.addWidget(self.play_pause_btn)
        layout.addWidget(self.stop_btn)
        layout.addWidget(self.current_time_label)
        layout.addWidget(self.position_slider, 1)  # Stretch
        layout.addWidget(self.duration_label)
        layout.addWidget(volume_label)
        layout.addWidget(self.volume_slider)
        
        # Enhanced styling
        self.setStyleSheet("""
            QWidget {
                background-color: rgba(0, 0, 0, 200);
                color: white;
            }
            QPushButton {
                border: 1px solid #555;
                border-radius: 5px;
                background-color: #333;
                font-weight: bold;
            }
            QPushButton:hover {
                background-color: #555;
            }
            QPushButton:pressed {
                background-color: #777;
            }
            QSlider::groove:horizontal {
                border: 1px solid #555;
                height: 6px;
                background: #222;
                border-radius: 3px;
            }
            QSlider::handle:horizontal {
                background: #fff;
                border: 2px solid #555;
                width: 14px;
                margin: -5px 0;
                border-radius: 7px;
            }
            QSlider::handle:horizontal:hover {
                background: #ddd;
            }
        """)
        
        self.slider_pressed = False
    
    def _on_slider_pressed(self):
        with QMutexLocker(self.mutex):
            self.slider_pressed = True
    
    def _on_slider_released(self):
        with QMutexLocker(self.mutex):
            self.slider_pressed = False
            self.seek_requested.emit(self.position_slider.value())
    
    def update_position(self, position: int, duration: int):
        """Update position display (thread-safe)"""
        with QMutexLocker(self.mutex):
            if not self.slider_pressed and duration > 0:
                self.position_slider.setValue(int(position * 100 / duration))
            
            self.current_time_label.setText(self._format_time(position))
            self.duration_label.setText(self._format_time(duration))
    
    def update_play_pause_button(self, is_playing: bool):
        """Update play/pause button state (thread-safe)"""
        with QMutexLocker(self.mutex):
            self.play_pause_btn.setText("⏸️" if is_playing else "▶️")
    
    def _format_time(self, ms: int) -> str:
        """Format time in milliseconds to MM:SS"""
        seconds = ms // 1000
        minutes = seconds // 60
        seconds = seconds % 60
        return f"{minutes:02d}:{seconds:02d}"


class PlayerWindow(QMainWindow):
    """Enhanced main player window with thread-safe operations"""
    
    # Signals for thread communication
    position_changed = pyqtSignal(int, int)
    video_loaded = pyqtSignal(str)
    
    def __init__(self, settings: QtConfig):
        super().__init__()
        self.settings = settings
        self.mutex = QMutex()
        self.thread_pool = QThreadPool()
        self.thread_pool.setMaxThreadCount(4)
        
        self.setup_ui()
        self.setup_media_player()
        self.setup_timers()
        
        logger.info("PlayerWindow initialized")
    
    def setup_ui(self):
        """Setup enhanced window UI"""
        self.setWindowTitle("MbetterClient - PyQt6 Video Player")
        self.setStyleSheet("background-color: black;")
        
        # Central widget
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        
        # Layout
        layout = QVBoxLayout(central_widget)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        
        # Video widget with overlay
        self.video_widget = VideoWidget()
        layout.addWidget(self.video_widget, 1)  # Stretch
        
        # Controls
        self.controls = PlayerControlsWidget()
        self.controls.play_pause_clicked.connect(self.toggle_play_pause)
        self.controls.stop_clicked.connect(self.stop_playback)
        self.controls.seek_requested.connect(self.seek_to_position)
        self.controls.volume_changed.connect(self.set_volume)
        layout.addWidget(self.controls)
        
        # Window settings
        if self.settings.fullscreen:
            self.showFullScreen()
        else:
            self.resize(self.settings.window_width, self.settings.window_height)
            self.show()
        
        if self.settings.always_on_top:
            self.setWindowFlags(self.windowFlags() | Qt.WindowType.WindowStaysOnTopHint)
        
        # Setup menu
        self.setup_menu()
    
    def setup_menu(self):
        """Setup application menu"""
        menubar = self.menuBar()
        
        # File menu
        file_menu = menubar.addMenu('File')
        
        open_action = QAction('Open Video', self)
        open_action.triggered.connect(self.open_file_dialog)
        file_menu.addAction(open_action)
        
        # View menu
        view_menu = menubar.addMenu('View')
        
        fullscreen_action = QAction('Toggle Fullscreen', self)
        fullscreen_action.setShortcut('F11')
        fullscreen_action.triggered.connect(self.toggle_fullscreen)
        view_menu.addAction(fullscreen_action)
        
        stats_action = QAction('Toggle Stats', self)
        stats_action.setShortcut('S')
        stats_action.triggered.connect(self.toggle_stats)
        view_menu.addAction(stats_action)
    
    def setup_media_player(self):
        """Setup PyQt6 media player with audio output"""
        self.media_player = QMediaPlayer()
        self.audio_output = QAudioOutput()
        
        self.media_player.setAudioOutput(self.audio_output)
        self.media_player.setVideoOutput(self.video_widget.get_video_widget())
        
        # Connect signals
        self.media_player.playbackStateChanged.connect(self.on_state_changed)
        self.media_player.positionChanged.connect(self.on_position_changed)
        self.media_player.durationChanged.connect(self.on_duration_changed)
        self.media_player.errorOccurred.connect(self.on_media_error)
        self.media_player.mediaStatusChanged.connect(self.on_media_status_changed)
        
        # Set volume
        self.audio_output.setVolume(self.settings.volume)
        self.audio_output.setMuted(self.settings.mute)
    
    def setup_timers(self):
        """Setup various timers"""
        # Auto-hide controls timer
        self.controls_timer = QTimer()
        self.controls_timer.timeout.connect(self.hide_controls)
        self.controls_timer.setSingleShot(True)
        
        # Overlay update timer
        self.overlay_timer = QTimer()
        self.overlay_timer.timeout.connect(self.update_overlay_periodically)
        self.overlay_timer.start(1000)  # Update every second
        
        # Mouse tracking for showing controls
        self.setMouseTracking(True)
        self.controls_visible = True
    
    def open_file_dialog(self):
        """Open file dialog to select video"""
        from PyQt6.QtWidgets import QFileDialog
        
        file_path, _ = QFileDialog.getOpenFileName(
            self,
            "Open Video File",
            "",
            "Video Files (*.mp4 *.avi *.mkv *.mov *.wmv *.flv *.webm *.m4v);;All Files (*)"
        )
        
        if file_path:
            self.play_video(file_path)
    
    def play_video(self, file_path: str, template_data: Dict[str, Any] = None, template_name: str = None):
        """Play video file with optional overlay data and template"""
        try:
            with QMutexLocker(self.mutex):
                url = QUrl.fromLocalFile(str(Path(file_path).absolute()))
                self.media_player.setSource(url)
                
                # Load specified template or reload current template when playing a video
                overlay_view = self.video_widget.get_overlay_view()
                if template_name:
                    overlay_view.load_template(template_name)
                    logger.info(f"Loaded template '{template_name}' for video playback")
                else:
                    overlay_view.reload_current_template()
                    logger.info("Reloaded current overlay template for video playback")
                
                # Update overlay with video info
                overlay_data = template_data or {}
                overlay_data.update({
                    'title': f'Playing: {Path(file_path).name}',
                    'subtitle': 'MbetterClient PyQt6 Player'
                })
                
                overlay_view.update_overlay_data(overlay_data)
                
                if self.settings.auto_play:
                    self.media_player.play()
                
                # Start background metadata extraction
                worker = VideoProcessingWorker(
                    "metadata_extraction",
                    {"file_path": file_path},
                    self.on_metadata_extracted
                )
                self.thread_pool.start(worker)
                
                logger.info(f"Playing video: {file_path}")
                self.video_loaded.emit(file_path)
                
        except Exception as e:
            logger.error(f"Failed to play video: {e}")
    
    def on_metadata_extracted(self, metadata: Dict[str, Any]):
        """Handle extracted metadata"""
        if 'error' not in metadata:
            self.video_widget.get_overlay_view().update_video_info(metadata)
            logger.debug(f"Video metadata: {metadata}")
    
    def toggle_play_pause(self):
        """Toggle play/pause (thread-safe)"""
        with QMutexLocker(self.mutex):
            if self.media_player.playbackState() == QMediaPlayer.PlaybackState.PlayingState:
                self.media_player.pause()
            else:
                self.media_player.play()
    
    def stop_playback(self):
        """Stop playback (thread-safe)"""
        with QMutexLocker(self.mutex):
            self.media_player.stop()
    
    def seek_to_position(self, percentage: int):
        """Seek to position (percentage) (thread-safe)"""
        with QMutexLocker(self.mutex):
            duration = self.media_player.duration()
            if duration > 0:
                position = int(duration * percentage / 100)
                self.media_player.setPosition(position)
    
    def set_volume(self, volume: int):
        """Set volume (0-100) (thread-safe)"""
        with QMutexLocker(self.mutex):
            self.audio_output.setVolume(volume / 100.0)
    
    def toggle_fullscreen(self):
        """Toggle fullscreen mode"""
        if self.isFullScreen():
            self.showNormal()
        else:
            self.showFullScreen()
    
    def toggle_stats(self):
        """Toggle stats panel"""
        overlay_view = self.video_widget.get_overlay_view()
        # Toggle stats via WebChannel
        if overlay_view.overlay_channel:
            current_stats = getattr(self, '_stats_visible', False)
            overlay_view.overlay_channel.toggleStats(not current_stats)
            self._stats_visible = not current_stats
    
    def on_state_changed(self, state):
        """Handle playback state changes (thread-safe)"""
        is_playing = state == QMediaPlayer.PlaybackState.PlayingState
        self.controls.update_play_pause_button(is_playing)
        
        # Auto-hide controls when playing in fullscreen
        if is_playing and self.isFullScreen():
            self.start_controls_timer()
    
    def on_position_changed(self, position):
        """Handle position changes (thread-safe)"""
        duration = self.media_player.duration()
        self.controls.update_position(position, duration)
        
        # Update overlay with position info
        if duration > 0:
            self.video_widget.get_overlay_view().update_position(
                position / 1000.0,  # Convert to seconds
                duration / 1000.0   # Convert to seconds
            )
        
        # Emit signal for other components
        self.position_changed.emit(position, duration)
    
    def on_duration_changed(self, duration):
        """Handle duration changes"""
        self.controls.update_position(self.media_player.position(), duration)
    
    def on_media_error(self, error):
        """Handle media errors"""
        logger.error(f"Media player error: {error}")
        
        # Show error in overlay
        self.video_widget.get_overlay_view().update_overlay_data({
            'title': 'Playback Error',
            'subtitle': f'Error: {error.name if hasattr(error, "name") else str(error)}',
            'ticker': 'Please check the video file and try again.'
        })
    
    def on_media_status_changed(self, status):
        """Handle media status changes"""
        logger.debug(f"Media status changed: {status}")
        
        if status == QMediaPlayer.MediaStatus.LoadedMedia:
            # Media loaded successfully
            self.video_widget.get_overlay_view().update_overlay_data({
                'subtitle': 'Media loaded successfully'
            })
    
    def update_overlay_periodically(self):
        """Periodic overlay updates"""
        # Update current time in overlay
        current_time = time.strftime("%H:%M:%S")
        self.video_widget.get_overlay_view().update_overlay_data({
            'currentTime': current_time
        })
    
    def mouseMoveEvent(self, event):
        """Show controls on mouse movement"""
        super().mouseMoveEvent(event)
        self.show_controls()
        
        if self.isFullScreen() and self.media_player.playbackState() == QMediaPlayer.PlaybackState.PlayingState:
            self.start_controls_timer()
    
    def keyPressEvent(self, event):
        """Handle key presses"""
        if event.key() == Qt.Key.Key_Space:
            self.toggle_play_pause()
        elif event.key() == Qt.Key.Key_Escape:
            if self.isFullScreen():
                self.showNormal()
            else:
                self.close()
        elif event.key() == Qt.Key.Key_F11:
            self.toggle_fullscreen()
        elif event.key() == Qt.Key.Key_M:
            current_muted = self.audio_output.isMuted()
            self.audio_output.setMuted(not current_muted)
        elif event.key() == Qt.Key.Key_S:
            self.toggle_stats()
        
        super().keyPressEvent(event)
    
    def show_controls(self):
        """Show controls"""
        if not self.controls_visible:
            self.controls.show()
            self.controls_visible = True
        self.setCursor(Qt.CursorShape.ArrowCursor)
    
    def hide_controls(self):
        """Hide controls"""
        if self.isFullScreen() and self.controls_visible:
            self.controls.hide()
            self.controls_visible = False
            self.setCursor(Qt.CursorShape.BlankCursor)
    
    def start_controls_timer(self):
        """Start timer to hide controls"""
        self.controls_timer.stop()
        self.controls_timer.start(3000)  # Hide after 3 seconds
    
    def closeEvent(self, event):
        """Handle window close (thread-safe)"""
        with QMutexLocker(self.mutex):
            self.media_player.stop()
            self.thread_pool.waitForDone(3000)  # Wait up to 3 seconds for threads
        event.accept()


class Qt6VideoPlayer(ThreadedComponent):
    """PyQt6 video player component with advanced features"""
    
    def __init__(self, message_bus: MessageBus, settings: QtConfig):
        super().__init__("qt6_player", message_bus)
        self.settings = settings
        self.app: Optional[QApplication] = None
        self.window: Optional[PlayerWindow] = None
        self.mutex = QMutex()
        
        # Register message queue
        self.message_queue = self.message_bus.register_component(self.name)
        
        logger.info("Qt6VideoPlayer initialized")
    
    def initialize(self) -> bool:
        """Initialize PyQt6 application and components"""
        try:
            with QMutexLocker(self.mutex):
                # Create QApplication if it doesn't exist
                if not QApplication.instance():
                    self.app = QApplication(sys.argv)
                    self.app.setApplicationName("MbetterClient PyQt6")
                    self.app.setApplicationVersion("2.0.0")
                    self.app.setQuitOnLastWindowClosed(True)
                else:
                    self.app = QApplication.instance()
                
                # Create player window
                self.window = PlayerWindow(self.settings)
                
                # Connect window signals
                self.window.position_changed.connect(self._on_position_changed)
                self.window.video_loaded.connect(self._on_video_loaded)
                
                # Subscribe to messages
                self.message_bus.subscribe(self.name, MessageType.VIDEO_PLAY, self._handle_video_play)
                self.message_bus.subscribe(self.name, MessageType.VIDEO_PAUSE, self._handle_video_pause)
                self.message_bus.subscribe(self.name, MessageType.VIDEO_STOP, self._handle_video_stop)
                self.message_bus.subscribe(self.name, MessageType.VIDEO_SEEK, self._handle_video_seek)
                self.message_bus.subscribe(self.name, MessageType.TEMPLATE_CHANGE, self._handle_template_change)
                self.message_bus.subscribe(self.name, MessageType.OVERLAY_UPDATE, self._handle_overlay_update)
                
                logger.info("Qt6VideoPlayer initialized successfully")
                return True
                
        except Exception as e:
            logger.error(f"Qt6VideoPlayer initialization failed: {e}")
            return False
    
    def run(self):
        """Main run loop"""
        try:
            logger.info("Qt6VideoPlayer thread started")
            
            # Send ready status
            ready_message = MessageBuilder.system_status(
                sender=self.name,
                status="ready",
                details={"fullscreen": self.settings.fullscreen, "version": "PyQt6-2.0.0"}
            )
            self.message_bus.publish(ready_message)
            
            # Message processing loop
            while self.running:
                try:
                    # Process Qt events
                    if self.app:
                        self.app.processEvents()
                    
                    # Process messages
                    message = self.message_bus.get_message(self.name, timeout=0.1)
                    if message:
                        self._process_message(message)
                    
                    # Update heartbeat
                    self.heartbeat()
                    
                    time.sleep(0.016)  # ~60 FPS
                    
                except Exception as e:
                    logger.error(f"Qt6VideoPlayer run loop error: {e}")
                    time.sleep(0.1)
                    
        except Exception as e:
            logger.error(f"Qt6VideoPlayer run failed: {e}")
        finally:
            logger.info("Qt6VideoPlayer thread ended")
    
    def shutdown(self):
        """Shutdown video player"""
        try:
            logger.info("Shutting down Qt6VideoPlayer...")
            
            with QMutexLocker(self.mutex):
                if self.window:
                    self.window.close()
                    self.window = None
                
                if self.app:
                    self.app.quit()
            
        except Exception as e:
            logger.error(f"Qt6VideoPlayer shutdown error: {e}")
    
    def _process_message(self, message: Message):
        """Process received message"""
        try:
            # Messages are handled by subscribed handlers
            pass
        except Exception as e:
            logger.error(f"Failed to process message: {e}")
    
    def _on_position_changed(self, position: int, duration: int):
        """Handle position changes from player window"""
        try:
            # Send progress update
            if duration > 0:
                percentage = (position / duration) * 100
                progress_message = MessageBuilder.video_progress(
                    sender=self.name,
                    position=position / 1000.0,  # Convert to seconds
                    duration=duration / 1000.0,  # Convert to seconds
                    percentage=percentage
                )
                self.message_bus.publish(progress_message, broadcast=True)
        except Exception as e:
            logger.error(f"Failed to send progress update: {e}")
    
    def _on_video_loaded(self, file_path: str):
        """Handle video loaded event"""
        try:
            logger.info(f"Video loaded: {file_path}")
            # Could send status update here
        except Exception as e:
            logger.error(f"Failed to handle video loaded event: {e}")
    
    def _handle_video_play(self, message: Message):
        """Handle video play message"""
        try:
            file_path = message.data.get("file_path")
            template_data = message.data.get("overlay_data", {})
            template_name = message.data.get("template")  # Extract template name from message
            
            if not file_path:
                logger.error("No file path provided for video play")
                return
            
            logger.info(f"Playing video: {file_path}")
            logger.info(f"Template name: {template_name}")
            
            if self.window:
                self.window.play_video(file_path, template_data, template_name)
            
        except Exception as e:
            logger.error(f"Failed to handle video play: {e}")
    
    def _handle_video_pause(self, message: Message):
        """Handle video pause message"""
        try:
            if self.window:
                self.window.media_player.pause()
        except Exception as e:
            logger.error(f"Failed to handle video pause: {e}")
    
    def _handle_video_stop(self, message: Message):
        """Handle video stop message"""
        try:
            if self.window:
                self.window.stop_playback()
        except Exception as e:
            logger.error(f"Failed to handle video stop: {e}")
    
    def _handle_video_seek(self, message: Message):
        """Handle video seek message"""
        try:
            position = message.data.get("position", 0)
            if self.window:
                duration = self.window.media_player.duration()
                if duration > 0:
                    percentage = int(position * 100 / duration)
                    self.window.seek_to_position(percentage)
        except Exception as e:
            logger.error(f"Failed to handle video seek: {e}")
    
    def _handle_template_change(self, message: Message):
        """Handle template change message"""
        try:
            template_data = message.data.get("template_data", {})
            template_name = template_data.get("template_name", "")
            change_type = template_data.get("change_type", "")
            
            if self.window:
                overlay_view = self.window.video_widget.get_overlay_view()
                
                # Reload template if it's the current one being used
                if template_name == overlay_view.current_template:
                    logger.info(f"Reloading template {template_name} due to {change_type}")
                    overlay_view.reload_current_template()
                
                # Update overlay data if provided
                if template_data:
                    overlay_view.update_overlay_data(template_data)
                
        except Exception as e:
            logger.error(f"Failed to handle template change: {e}")
    
    def _handle_overlay_update(self, message: Message):
        """Handle overlay update message"""
        try:
            overlay_data = message.data.get("overlay_data", {})
            
            if self.window and overlay_data:
                overlay_view = self.window.video_widget.get_overlay_view()
                overlay_view.update_overlay_data(overlay_data)
                
        except Exception as e:
            logger.error(f"Failed to handle overlay update: {e}")