"""
PyQt video player with overlay support
"""

import sys
import time
import logging
from pathlib import Path
from typing import Optional, Dict, Any
from PyQt5.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QLabel, QPushButton, QSlider, QFrame, QGraphicsView, QGraphicsScene,
    QGraphicsProxyWidget
)
from PyQt5.QtCore import (
    Qt, QTimer, QThread, pyqtSignal, QUrl, QRect, QPropertyAnimation,
    QEasingCurve, QSequentialAnimationGroup
)
from PyQt5.QtGui import (
    QFont, QPainter, QPen, QBrush, QColor, QPixmap, QMovie, 
    QLinearGradient, QFontMetrics
)
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContent
from PyQt5.QtMultimediaWidgets import QVideoWidget

from ..core.thread_manager import ThreadedComponent
from ..core.message_bus import MessageBus, Message, MessageType, MessageBuilder
from ..config.settings import QtConfig
from .overlay_engine import OverlayEngine
from .templates import TemplateManager

logger = logging.getLogger(__name__)


class OverlayWidget(QWidget):
    """Transparent overlay widget for rendering overlays on top of video"""
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.overlay_engine = None
        self.setAttribute(Qt.WA_TransparentForMouseEvents, False)  # Allow mouse events
        self.setStyleSheet("background-color: transparent;")
        
        # Timer to force repaints for overlay rendering
        self.repaint_timer = QTimer()
        self.repaint_timer.timeout.connect(self.update)
        self.repaint_timer.start(33)  # ~30 FPS for smooth overlays
        
        logger.info("OverlayWidget initialized with repaint timer")
    
    def set_overlay_engine(self, overlay_engine):
        """Set overlay engine for rendering"""
        self.overlay_engine = overlay_engine
        logger.info("Overlay engine set on overlay widget")
    
    def paintEvent(self, event):
        """Custom paint event to render overlays"""
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        
        # Render overlays if available
        if self.overlay_engine:
            try:
                element_count = len(self.overlay_engine.renderer.elements)
                if element_count > 0:
                    logger.debug(f"OverlayWidget paintEvent: Rendering {element_count} overlay elements")
                    self.overlay_engine.render(painter, self.rect())
                else:
                    logger.debug("OverlayWidget paintEvent: No overlay elements to render")
                    
            except Exception as e:
                logger.error(f"Overlay rendering error: {e}")
                import traceback
                logger.error(f"Overlay rendering traceback: {traceback.format_exc()}")
        else:
            logger.debug("OverlayWidget paintEvent: No overlay engine available")
        
        painter.end()


class VideoWidget(QWidget):
    """Composite video widget with overlay support that always works"""
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.overlay_engine = None
        self.setStyleSheet("background-color: black;")
        
        # Create layout
        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        layout.setSpacing(0)
        
        # Create video widget for actual video playback
        self.video_widget = QVideoWidget()
        self.video_widget.setStyleSheet("background-color: black;")
        layout.addWidget(self.video_widget)
        
        # Create overlay widget that sits on top
        self.overlay_widget = OverlayWidget()
        self.overlay_widget.setParent(self)
        
        logger.info("Composite VideoWidget initialized")
    
    def set_overlay_engine(self, overlay_engine):
        """Set overlay engine for rendering"""
        self.overlay_engine = overlay_engine
        self.overlay_widget.set_overlay_engine(overlay_engine)
        logger.info("Overlay engine set on composite video widget")
    
    def resizeEvent(self, event):
        """Ensure overlay widget covers the entire video widget"""
        super().resizeEvent(event)
        self.overlay_widget.resize(self.size())
        self.overlay_widget.move(0, 0)
    
    def get_video_widget(self):
        """Get the actual QVideoWidget for media player"""
        return self.video_widget


class PlayerControlsWidget(QWidget):
    """Video player controls"""
    
    play_pause_clicked = pyqtSignal()
    stop_clicked = pyqtSignal()
    seek_requested = pyqtSignal(int)
    
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setup_ui()
    
    def setup_ui(self):
        """Setup 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.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)
        
        # Time labels
        self.current_time_label = QLabel("00:00")
        self.duration_label = QLabel("00:00")
        
        # 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)
        
        # Style
        self.setStyleSheet("""
            QWidget {
                background-color: rgba(0, 0, 0, 180);
                color: white;
            }
            QPushButton {
                border: 1px solid #555;
                border-radius: 3px;
                background-color: #333;
            }
            QPushButton:hover {
                background-color: #555;
            }
            QSlider::groove:horizontal {
                border: 1px solid #555;
                height: 4px;
                background: #222;
            }
            QSlider::handle:horizontal {
                background: #fff;
                border: 1px solid #555;
                width: 12px;
                margin: -4px 0;
                border-radius: 6px;
            }
        """)
        
        self.slider_pressed = False
    
    def _on_slider_pressed(self):
        self.slider_pressed = True
    
    def _on_slider_released(self):
        self.slider_pressed = False
        self.seek_requested.emit(self.position_slider.value())
    
    def update_position(self, position: int, duration: int):
        """Update position display"""
        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"""
        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):
    """Main player window"""
    
    def __init__(self, settings: QtConfig, overlay_engine: OverlayEngine):
        super().__init__()
        self.settings = settings
        self.overlay_engine = overlay_engine
        self.setup_ui()
        self.setup_media_player()
        
        # Auto-hide controls timer
        self.controls_timer = QTimer()
        self.controls_timer.timeout.connect(self.hide_controls)
        self.controls_timer.setSingleShot(True)
        
        # Mouse tracking for showing controls
        self.setMouseTracking(True)
        self.controls_visible = True
    
    def setup_ui(self):
        """Setup window UI"""
        self.setWindowTitle("MbetterClient 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
        self.video_widget = VideoWidget()
        self.video_widget.set_overlay_engine(self.overlay_engine)
        layout.addWidget(self.video_widget, 1)  # Stretch
        
        logger.info(f"Composite video widget created with overlay engine: {self.overlay_engine is not None}")
        
        # 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)
        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.WindowStaysOnTopHint)
    
    def setup_media_player(self):
        """Setup media player"""
        self.media_player = QMediaPlayer(None, QMediaPlayer.VideoSurface)
        self.media_player.setVideoOutput(self.video_widget.get_video_widget())
        
        # Connect signals
        self.media_player.stateChanged.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.error.connect(self.on_media_error)
        
        # Set volume
        self.media_player.setVolume(int(self.settings.volume * 100))
        self.media_player.setMuted(self.settings.mute)
    
    def play_video(self, file_path: str):
        """Play video file"""
        try:
            url = QUrl.fromLocalFile(str(Path(file_path).absolute()))
            content = QMediaContent(url)
            self.media_player.setMedia(content)
            
            if self.settings.auto_play:
                self.media_player.play()
            
            logger.info(f"Playing video: {file_path}")
            
        except Exception as e:
            logger.error(f"Failed to play video: {e}")
    
    def toggle_play_pause(self):
        """Toggle play/pause"""
        if self.media_player.state() == QMediaPlayer.PlayingState:
            self.media_player.pause()
        else:
            self.media_player.play()
    
    def stop_playback(self):
        """Stop playback"""
        self.media_player.stop()
    
    def seek_to_position(self, percentage: int):
        """Seek to position (percentage)"""
        duration = self.media_player.duration()
        if duration > 0:
            position = int(duration * percentage / 100)
            self.media_player.setPosition(position)
    
    def on_state_changed(self, state):
        """Handle state changes"""
        is_playing = state == QMediaPlayer.PlayingState
        self.controls.update_play_pause_button(is_playing)
        
        # Auto-hide controls when playing in fullscreen
        if is_playing and self.settings.fullscreen:
            self.start_controls_timer()
    
    def on_position_changed(self, position):
        """Handle position changes"""
        duration = self.media_player.duration()
        self.controls.update_position(position, duration)
        
        # Update overlay engine with current position
        if self.overlay_engine:
            self.overlay_engine.update_playback_position(position, duration)
        
        # Trigger overlay repaint on the overlay widget
        if hasattr(self.video_widget, 'overlay_widget'):
            self.video_widget.overlay_widget.update()
    
    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}")
    
    def mouseMoveEvent(self, event):
        """Show controls on mouse movement"""
        super().mouseMoveEvent(event)
        self.show_controls()
        
        if self.settings.fullscreen and self.media_player.state() == QMediaPlayer.PlayingState:
            self.start_controls_timer()
    
    def keyPressEvent(self, event):
        """Handle key presses"""
        if event.key() == Qt.Key_Space:
            self.toggle_play_pause()
        elif event.key() == Qt.Key_Escape:
            if self.isFullScreen():
                self.showNormal()
            else:
                self.close()
        elif event.key() == Qt.Key_F11:
            if self.isFullScreen():
                self.showNormal()
            else:
                self.showFullScreen()
        elif event.key() == Qt.Key_M:
            self.media_player.setMuted(not self.media_player.isMuted())
        
        super().keyPressEvent(event)
    
    def show_controls(self):
        """Show controls"""
        if not self.controls_visible:
            self.controls.show()
            self.controls_visible = True
        self.setCursor(Qt.ArrowCursor)
    
    def hide_controls(self):
        """Hide controls"""
        if self.settings.fullscreen and self.controls_visible:
            self.controls.hide()
            self.controls_visible = False
            self.setCursor(Qt.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"""
        self.media_player.stop()
        event.accept()


class QtVideoPlayer(ThreadedComponent):
    """Qt video player component"""
    
    def __init__(self, message_bus: MessageBus, settings: QtConfig):
        super().__init__("qt_player", message_bus)
        self.settings = settings
        self.app: Optional[QApplication] = None
        self.window: Optional[PlayerWindow] = None
        self.overlay_engine: Optional[OverlayEngine] = None
        self.template_manager: Optional[TemplateManager] = None
        
        # Register message queue
        self.message_queue = self.message_bus.register_component(self.name)
        
        logger.info("QtVideoPlayer initialized")
    
    def initialize(self) -> bool:
        """Initialize PyQt application and components"""
        try:
            # Create QApplication if it doesn't exist
            if not QApplication.instance():
                self.app = QApplication(sys.argv)
                self.app.setApplicationName("MbetterClient")
                self.app.setQuitOnLastWindowClosed(True)
            else:
                self.app = QApplication.instance()
            
            # Initialize overlay engine
            self.overlay_engine = OverlayEngine()
            
            # Initialize template manager
            self.template_manager = TemplateManager()
            
            # Create player window
            self.window = PlayerWindow(self.settings, self.overlay_engine)
            
            # Load default template
            self._load_default_template()
            
            # 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("QtVideoPlayer initialized successfully")
            return True
            
        except Exception as e:
            logger.error(f"QtVideoPlayer initialization failed: {e}")
            return False
    
    def _load_default_template(self):
        """Load default template for display"""
        try:
            logger.info("Starting default template loading...")
            
            if not self.template_manager:
                logger.error("Template manager not initialized")
                return
                
            if not self.overlay_engine:
                logger.error("Overlay engine not initialized")
                return
                
            logger.info("Template manager and overlay engine are initialized")
            
            # Load simple template by default
            template_config = self.template_manager.get_template('simple_template')
            logger.info(f"Template config retrieved: {template_config is not None}")
            
            if template_config:
                logger.info(f"Template config keys: {list(template_config.keys())}")
                logger.info(f"Template elements count: {len(template_config.get('elements', []))}")
                
                overlay_data = {
                    'simple_text': {'text': 'MbetterClient - Ready to Play'},
                    'timestamp': {'text': 'Waiting for video...'}
                }
                logger.info(f"Overlay data: {overlay_data}")
                
                self.overlay_engine.load_template(template_config, overlay_data)
                
                # Verify elements were loaded
                elements_loaded = list(self.overlay_engine.renderer.elements.keys())
                logger.info(f"Overlay elements loaded: {elements_loaded}")
                
                if elements_loaded:
                    logger.info("Default template loaded successfully")
                else:
                    logger.warning("Default template loaded but no elements created")
                    
            else:
                logger.error("Default template not found in template manager")
                available_templates = self.template_manager.get_template_names()
                logger.info(f"Available templates: {available_templates}")
                
        except Exception as e:
            logger.error(f"Failed to load default template: {e}")
            import traceback
            logger.error(f"Template loading traceback: {traceback.format_exc()}")
    
    def run(self):
        """Main run loop"""
        try:
            logger.info("QtVideoPlayer thread started")
            
            # Send ready status
            ready_message = MessageBuilder.system_status(
                sender=self.name,
                status="ready",
                details={"fullscreen": self.settings.fullscreen}
            )
            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)
                    
                    # Send periodic progress updates if playing
                    if (self.window and self.window.media_player.state() == QMediaPlayer.PlayingState):
                        self._send_progress_update()
                    
                    # Force overlay updates to keep animations smooth
                    if self.window and self.window.video_widget:
                        if self.overlay_engine and len(self.overlay_engine.renderer.elements) > 0:
                            logger.debug("Main loop: Triggering video widget overlay update")
                        else:
                            logger.debug("Main loop: No overlay elements available")
                        # The video widget now handles its own repaints via timer
                    
                    # Update heartbeat
                    self.heartbeat()
                    
                    time.sleep(0.016)  # ~60 FPS
                    
                except Exception as e:
                    logger.error(f"QtVideoPlayer run loop error: {e}")
                    time.sleep(0.1)
                    
        except Exception as e:
            logger.error(f"QtVideoPlayer run failed: {e}")
        finally:
            logger.info("QtVideoPlayer thread ended")
    
    def shutdown(self):
        """Shutdown video player"""
        try:
            logger.info("Shutting down QtVideoPlayer...")
            
            if self.window:
                self.window.close()
                self.window = None
            
            if self.app:
                self.app.quit()
            
        except Exception as e:
            logger.error(f"QtVideoPlayer 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 _handle_video_play(self, message: Message):
        """Handle video play message"""
        try:
            file_path = message.data.get("file_path")
            template = message.data.get("template", "news_template")
            overlay_data = message.data.get("overlay_data", {})
            
            if not file_path:
                logger.error("No file path provided for video play")
                return
            
            logger.info(f"Playing video: {file_path} with template: {template}")
            
            # Load template
            if self.template_manager:
                template_config = self.template_manager.get_template(template)
                if template_config:
                    self.overlay_engine.load_template(template_config, overlay_data)
            
            # Play video
            if self.window:
                self.window.play_video(file_path)
            
        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_name = message.data.get("template_name")
            template_data = message.data.get("template_data", {})
            
            if self.template_manager and template_name:
                template_config = self.template_manager.get_template(template_name)
                if template_config and self.overlay_engine:
                    self.overlay_engine.load_template(template_config, 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.overlay_engine:
                self.overlay_engine.update_overlay_data(overlay_data)
                
        except Exception as e:
            logger.error(f"Failed to handle overlay update: {e}")
    
    def _send_progress_update(self):
        """Send video progress update"""
        try:
            if self.window and self.window.media_player.duration() > 0:
                position = self.window.media_player.position()
                duration = self.window.media_player.duration()
                percentage = (position / duration) * 100 if duration > 0 else 0
                
                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}")