from PyQt5.QtWidgets import (
    QWidget, QHBoxLayout, QVBoxLayout, QSlider, QLabel, 
    QPushButton, QComboBox, QFrame, QSizePolicy, QToolTip
)
from PyQt5.QtCore import Qt, QTimer, pyqtSignal, QPoint
from PyQt5.QtGui import QFont, QPainter, QPen, QBrush, QColor, QPainterPath, QPolygon

from gui.assets.theme.styler import current_theme
from gui.widgets.help_button import HelpButton


class IconButton(QPushButton):
    
    ICON_START = "start"      
    ICON_BACK = "back"        
    ICON_PLAY = "play"        
    ICON_PAUSE = "pause"      
    ICON_FORWARD = "forward"  
    ICON_END = "end"          
    
    def __init__(self, icon_type, parent=None):
        super().__init__(parent)
        self._icon_type = icon_type
        self._hovered = False
        self._pressed = False
        
        self.setFixedSize(36, 36)
        self.setCursor(Qt.PointingHandCursor)
        self.setMouseTracking(True)
    
    def set_icon_type(self, icon_type):
        self._icon_type = icon_type
        self.update()
    
    def enterEvent(self, event):
        self._hovered = True
        self.update()
        super().enterEvent(event)
    
    def leaveEvent(self, event):
        self._hovered = False
        self.update()
        super().leaveEvent(event)
    
    def mousePressEvent(self, event):
        self._pressed = True
        self.update()
        super().mousePressEvent(event)
    
    def mouseReleaseEvent(self, event):
        self._pressed = False
        self.update()
        super().mouseReleaseEvent(event)
    
    def paintEvent(self, event):
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        
        rect = self.rect()
        
        bg_color = QColor(current_theme.get('background_secondary', '#1F2937'))
        bg_hover = QColor(current_theme.get('background_tertiary', '#4B5563'))
        bg_pressed = QColor(current_theme.get('interactive_primary', '#3B82F6'))
        border_color = QColor(current_theme.get('background_tertiary', '#4B5563'))
        icon_color = QColor(current_theme.get('text_primary', '#F9FAFB'))
        
        if self._pressed:
            bg = bg_pressed
        elif self._hovered:
            bg = bg_hover
        else:
            bg = bg_color
        
        path = QPainterPath()
        path.addRoundedRect(1, 1, rect.width() - 2, rect.height() - 2, 6, 6)
        
        painter.setPen(QPen(border_color, 1))
        painter.setBrush(QBrush(bg))
        painter.drawPath(path)
        
        painter.setPen(Qt.NoPen)
        painter.setBrush(QBrush(icon_color))
        
        cx = rect.width() / 2
        cy = rect.height() / 2
        
        if self._icon_type == self.ICON_START:
            painter.fillRect(int(cx - 8), int(cy - 6), 3, 12, icon_color)
            self._draw_triangle(painter, cx + 6, cy, 8, "left", icon_color)
            
        elif self._icon_type == self.ICON_BACK:
            self._draw_triangle(painter, cx + 2, cy, 10, "left", icon_color)
            
        elif self._icon_type == self.ICON_PLAY:
            self._draw_triangle(painter, cx - 2, cy, 12, "right", icon_color)
            
        elif self._icon_type == self.ICON_PAUSE:
            painter.fillRect(int(cx - 6), int(cy - 6), 4, 12, icon_color)
            painter.fillRect(int(cx + 2), int(cy - 6), 4, 12, icon_color)
            
        elif self._icon_type == self.ICON_FORWARD:
            self._draw_triangle(painter, cx - 2, cy, 10, "right", icon_color)
            
        elif self._icon_type == self.ICON_END:
            self._draw_triangle(painter, cx - 6, cy, 8, "right", icon_color)
            painter.fillRect(int(cx + 5), int(cy - 6), 3, 12, icon_color)
        
        painter.end()
    
    def _draw_triangle(self, painter, x, y, size, direction, color):
        half = size / 2
        
        if direction == "right":
            points = [
                QPoint(int(x), int(y - half)),
                QPoint(int(x + size), int(y)),
                QPoint(int(x), int(y + half))
            ]
        else:
            points = [
                QPoint(int(x), int(y - half)),
                QPoint(int(x - size), int(y)),
                QPoint(int(x), int(y + half))
            ]
        
        painter.setPen(Qt.NoPen)
        painter.setBrush(QBrush(color))
        painter.drawPolygon(QPolygon(points))


class StyledSlider(QSlider):
    def __init__(self, orientation, parent=None):
        super().__init__(orientation, parent)
        self._format_func = None
        self.setMouseTracking(True)
    
    def set_format_function(self, func):
        self._format_func = func
    
    def mouseMoveEvent(self, event):
        if self.maximum() > 0:
            pos = event.pos().x()
            width = self.width()
            value = int((pos / width) * self.maximum())
            value = max(0, min(value, self.maximum()))
            
            if self._format_func:
                text = self._format_func(value)
            else:
                text = str(value)
            
            QToolTip.showText(event.globalPos(), text, self)
        
        super().mouseMoveEvent(event)
    
    def apply_style(self):
        bg_secondary = current_theme.get('background_secondary', '#1F2937')
        bg_tertiary = current_theme.get('background_tertiary', '#4B5563')
        interactive = current_theme.get('interactive_primary', '#3B82F6')
        
        self.setStyleSheet(f"""
            QSlider::groove:horizontal {{
                background: {bg_tertiary};
                height: 6px;
                border-radius: 3px;
            }}
            QSlider::handle:horizontal {{
                background: {interactive};
                width: 16px;
                height: 16px;
                margin: -5px 0;
                border-radius: 8px;
            }}
            QSlider::handle:horizontal:hover {{
                background: #2563EB;
            }}
            QSlider::sub-page:horizontal {{
                background: {interactive};
                border-radius: 3px;
            }}
        """)


class TimelineWidget(QFrame):
    time_changed = pyqtSignal(int)
    play_state_changed = pyqtSignal(bool)
    
    STEP_MS = 100
    
    def __init__(self, parent=None):
        super().__init__(parent)
        
        self._max_time_ms = 0
        self._current_time_ms = 0
        self._current_cycle = 0
        self._is_playing = False
        self._playback_speed = 1.0
        self._is_live = True
        
        self._playback_timer = QTimer()
        self._playback_timer.timeout.connect(self._on_playback_tick)
        
        self.setMinimumHeight(90)
        self.setMaximumHeight(100)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Fixed)
        
        self._setup_ui()
        self._apply_styles()
    
    def _setup_ui(self):
        main_layout = QVBoxLayout(self)
        main_layout.setContentsMargins(16, 10, 16, 10)
        main_layout.setSpacing(6)
        
        header_layout = QHBoxLayout()
        header_layout.setSpacing(12)
        
        title = QLabel("Timeline")
        title.setFont(QFont("Segoe UI", 11, QFont.Bold))
        title.setMinimumWidth(60)
        
        self.help_button = HelpButton(
            "<div style='max-width: 450px;'>"
            "<h3 style='margin: 0 0 10px 0; color: #3B82F6;'>Timeline</h3>"
            "<p style='margin: 0 0 10px 0;'>The Timeline allows you to navigate through the simulation history and review past states</p>"
            "<p style='margin: 0 0 5px 0;'><b>Live Mode:</b> Shows real-time data as logs arrive from the simulation</p>"
            "<p style='margin: 0 0 10px 0;'><b>Historical Mode:</b> Activated when you move the slider backward to review past states</p>"
            "<p style='margin: 0 0 5px 0;'><b>|◀ Go to Start:</b> Jump to the beginning of the simulation</p>"
            "<p style='margin: 0 0 5px 0;'><b>◀ Step Back:</b> Go back 100ms in the timeline</p>"
            "<p style='margin: 0 0 5px 0;'><b>▶ Play/Pause:</b> Auto-play through the simulation history</p>"
            "<p style='margin: 0 0 5px 0;'><b>▶ Step Forward:</b> Advance 100ms in the timeline</p>"
            "<p style='margin: 0 0 5px 0;'><b>▶| Go to End:</b> Return to Live mode and see the latest data</p>"
            "</div>",
            icon_size=23
        )
        
        self.mode_label = QLabel("LIVE")
        self.mode_label.setFont(QFont("Segoe UI", 10, QFont.Bold))
        self.mode_label.setStyleSheet("color: #10B981;")
        self.mode_label.setMinimumWidth(80)
        
        speed_label = QLabel("Speed:")
        speed_label.setFont(QFont("Segoe UI", 10))
        
        self.speed_combo = QComboBox()
        self.speed_combo.addItems(["0.25x", "0.5x", "1x", "2x", "4x", "8x"])
        self.speed_combo.setCurrentText("1x")
        self.speed_combo.currentTextChanged.connect(self._on_speed_changed)
        self.speed_combo.setFixedWidth(70)
        
        header_layout.addWidget(title)
        header_layout.addWidget(self.help_button)
        header_layout.addWidget(self.mode_label)
        header_layout.addStretch()
        header_layout.addWidget(speed_label)
        header_layout.addWidget(self.speed_combo)
        
        main_layout.addLayout(header_layout)
        
        controls_layout = QHBoxLayout()
        controls_layout.setSpacing(6)
        
        self.btn_start = IconButton(IconButton.ICON_START)
        self.btn_start.setToolTip("Go to Start")
        self.btn_start.clicked.connect(self._go_to_start)
        
        self.btn_back = IconButton(IconButton.ICON_BACK)
        self.btn_back.setToolTip("Step Back (100ms)")
        self.btn_back.clicked.connect(self._step_back)
        
        self.btn_play = IconButton(IconButton.ICON_PLAY)
        self.btn_play.setToolTip("Play")
        self.btn_play.clicked.connect(self._toggle_play)
        
        self.btn_forward = IconButton(IconButton.ICON_FORWARD)
        self.btn_forward.setToolTip("Step Forward (100ms)")
        self.btn_forward.clicked.connect(self._step_forward)
        
        self.btn_end = IconButton(IconButton.ICON_END)
        self.btn_end.setToolTip("Go to End")
        self.btn_end.clicked.connect(self._go_to_end)
        
        controls_layout.addWidget(self.btn_start)
        controls_layout.addWidget(self.btn_back)
        controls_layout.addWidget(self.btn_play)
        controls_layout.addWidget(self.btn_forward)
        controls_layout.addWidget(self.btn_end)
        
        controls_layout.addSpacing(12)
        
        self.slider = StyledSlider(Qt.Horizontal)
        self.slider.setMinimum(0)
        self.slider.setMaximum(0)
        self.slider.set_format_function(self._format_time_full)
        self.slider.valueChanged.connect(self._on_slider_changed)
        controls_layout.addWidget(self.slider, stretch=1)
        
        controls_layout.addSpacing(12)
        
        self.time_label = QLabel("00:00:00.000 / 00:00:00.000")
        self.time_label.setFont(QFont("Segoe UI", 10))
        self.time_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.time_label.setMinimumWidth(180)
        
        self.cycle_label = QLabel("Cycle: 0")
        self.cycle_label.setFont(QFont("Segoe UI", 9))
        self.cycle_label.setProperty("class", "text-secondary")
        self.cycle_label.setAlignment(Qt.AlignRight | Qt.AlignVCenter)
        self.cycle_label.setMinimumWidth(70)
        
        controls_layout.addWidget(self.time_label)
        controls_layout.addWidget(self.cycle_label)
        
        main_layout.addLayout(controls_layout)
    
    def _apply_styles(self):
        bg_primary = current_theme.get('background_primary', '#111827')
        bg_secondary = current_theme.get('background_secondary', '#1F2937')
        bg_tertiary = current_theme.get('background_tertiary', '#4B5563')
        text_primary = current_theme.get('text_primary', '#F9FAFB')
        text_secondary = current_theme.get('text_secondary', '#9CA3AF')
        interactive = current_theme.get('interactive_primary', '#3B82F6')
        
        self.setStyleSheet(f"""
            TimelineWidget {{
                background-color: {bg_secondary};
                border: 1px solid {bg_tertiary};
                border-radius: 10px;
            }}
            QLabel {{
                color: {text_primary};
                background: transparent;
            }}
            QLabel[class="text-secondary"] {{
                color: {text_secondary};
            }}
            QComboBox {{
                background-color: {bg_tertiary};
                border: 1px solid {bg_tertiary};
                border-radius: 4px;
                padding: 4px 8px;
                color: {text_primary};
                font-size: 11px;
            }}
            QComboBox:hover {{
                border-color: {interactive};
            }}
            QComboBox::drop-down {{
                border: none;
            }}
            QComboBox QAbstractItemView {{
                background-color: {bg_secondary};
                border: 1px solid {bg_tertiary};
                selection-background-color: {interactive};
                color: {text_primary};
            }}
        """)
        
        self.slider.apply_style()
    
    def _format_time(self, ms):
        seconds = ms // 1000
        minutes = seconds // 60
        hours = minutes // 60
        
        return f"{hours:02d}:{minutes % 60:02d}:{seconds % 60:02d}"
    
    def _format_time_full(self, ms):
        milliseconds = ms % 1000
        seconds = ms // 1000
        minutes = seconds // 60
        hours = minutes // 60
        
        return f"{hours:02d}:{minutes % 60:02d}:{seconds % 60:02d}.{milliseconds:03d}"
    
    def _update_display(self):
        current_str = self._format_time_full(self._current_time_ms)
        max_str = self._format_time_full(self._max_time_ms)
        
        self.time_label.setText(f"{current_str} / {max_str}")
        self.cycle_label.setText(f"Cycle: {self._current_cycle}")
    
    def set_range(self, max_time_ms):
        self._max_time_ms = max_time_ms
        self.slider.setMaximum(max_time_ms)
        self._update_display()
    
    def set_time(self, time_ms, cycle=None, block_signals=False):
        self._current_time_ms = time_ms
        if cycle is not None:
            self._current_cycle = cycle
        
        if block_signals:
            self.slider.blockSignals(True)
        
        self.slider.setValue(time_ms)
        
        if block_signals:
            self.slider.blockSignals(False)
        
        self._update_display()
    
    def set_cycle(self, cycle):
        self._current_cycle = cycle
        self._update_display()
    
    def get_time(self):
        return self._current_time_ms
    
    def is_playing(self):
        return self._is_playing
    
    def is_live(self):
        return self._is_live
    
    def set_live(self, is_live):
        self._is_live = is_live

    def _go_to_start(self):
        self._is_live = False
        self._stop_playback()
        self.slider.setValue(0)
    
    def _step_back(self):
        self._is_live = False
        new_value = max(0, self._current_time_ms - self.STEP_MS)
        self.slider.setValue(new_value)
    
    def _toggle_play(self):
        if self._is_playing:
            self._stop_playback()
        else:
            self._start_playback()
    
    def _step_forward(self):
        new_value = min(self._max_time_ms, self._current_time_ms + self.STEP_MS)
        
        if new_value >= self._max_time_ms:
            self._is_live = True
        
        self.slider.setValue(new_value)
    
    def _go_to_end(self):
        self._is_live = True
        self._stop_playback()
        self.slider.setValue(self._max_time_ms)
    
    def _start_playback(self):
        self._is_playing = True
        self._is_live = False
        self.btn_play.set_icon_type(IconButton.ICON_PAUSE)
        self.btn_play.setToolTip("Pause")
        
        interval = int(50 / self._playback_speed)
        self._playback_timer.start(max(10, interval))
        
        self.play_state_changed.emit(True)
    
    def _stop_playback(self):
        self._is_playing = False
        self._playback_timer.stop()
        self.btn_play.set_icon_type(IconButton.ICON_PLAY)
        self.btn_play.setToolTip("Play")
        
        self.play_state_changed.emit(False)
    
    def _on_playback_tick(self):
        step = int(50 * self._playback_speed)
        new_value = self._current_time_ms + step
        
        if new_value >= self._max_time_ms:
            new_value = self._max_time_ms
            self._stop_playback()
            self._is_live = True
        
        self.slider.setValue(new_value)
    
    def _on_speed_changed(self, speed_text):
        speed_map = {
            "0.25x": 0.25,
            "0.5x": 0.5,
            "1x": 1.0,
            "2x": 2.0,
            "4x": 4.0,
            "8x": 8.0
        }
        self._playback_speed = speed_map.get(speed_text, 1.0)
        
        if self._is_playing:
            self._playback_timer.stop()
            interval = int(50 / self._playback_speed)
            self._playback_timer.start(max(10, interval))
    
    def _on_slider_changed(self, value):
        self._current_time_ms = value
        self._update_display()
        
        self.time_changed.emit(value)
    
    def update_theme(self):
        self._apply_styles()
        self.update()