# Copyright (c) 2026, UChicago Argonne, LLC
# BSD OPEN SOURCE LICENSE. Full license can be found in LICENSE
# Copyright (c) 2026, UChicago Argonne, LLC
# BSD OPEN SOURCE LICENSE. Full license can be found in LICENSE
from qgis.PyQt.QtCore import Qt, pyqtSignal, QRect, QPoint
from qgis.PyQt.QtGui import QPainter, QColor, QPen, QLinearGradient
from qgis.PyQt.QtWidgets import QSlider


class SingleBarDoubleSlider(QSlider):
    """
    Elegant, minimalist single bar double slider
    """

    rangeChanged = pyqtSignal(int, int)

    def __init__(self, min_val, max_val, orientation=Qt.Horizontal, parent=None):
        super().__init__(orientation, parent)

        # Slider state
        self._low_value = min_val
        self._high_value = max_val

        # Customize appearance
        self.setMinimum(min_val)
        self.setMaximum(max_val)

        # Styling
        self.setStyleSheet(
            """
            QSlider::groove:horizontal {
                background: #E0E0E0;
                height: 6px;
                border-radius: 3px;
            }
            QSlider::handle:horizontal {
                background: white;
                border: 2px solid #4A90E2;
                width: 16px;
                height: 16px;
                margin: -5px 0;
                border-radius: 8px;
                box-shadow: 0 1px 3px rgba(0,0,0,0.1);
            }
            QSlider::handle:horizontal:hover {
                background: #F0F0F0;
            }
        """
        )

    def setLowValue(self, value):
        """Set the position of the lower handle"""
        # Ensure value is within bounds
        value = max(self.minimum(), min(value, self._high_value))
        if value != self._low_value:
            self._low_value = value
            self.update()
            self.rangeChanged.emit(self._low_value, self._high_value)

    def setHighValue(self, value):
        """Set the position of the higher handle"""
        # Ensure value is within bounds
        value = max(self._low_value, min(value, self.maximum()))
        if value != self._high_value:
            self._high_value = value
            self.update()
            self.rangeChanged.emit(self._low_value, self._high_value)

    def getLowValue(self):
        """Get the current position of the lower handle"""
        return self._low_value

    def getHighValue(self):
        """Get the current position of the higher handle"""
        return self._high_value

    def setRange(self, low, high):
        """Set both handle positions simultaneously"""
        # Ensure values are within bounds and in correct order
        low = max(self.minimum(), min(low, high))
        high = max(low, min(high, self.maximum()))

        if low != self._low_value or high != self._high_value:
            self._low_value = low
            self._high_value = high
            self.update()
            self.rangeChanged.emit(self._low_value, self._high_value)

    def paintEvent(self, event):
        """Custom paint event to draw the range"""
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)

        # Get slider geometry
        groove_rect = self.rect()
        groove_rect.setHeight(6)
        groove_rect.moveCenter(self.rect().center())

        # Draw filled range
        filled_rect = QRect(groove_rect)
        filled_rect.setLeft(self.valueToPixel(self._low_value))
        filled_rect.setRight(self.valueToPixel(self._high_value))

        # Soft gradient for range
        gradient = QLinearGradient(filled_rect.topLeft(), filled_rect.topRight())
        gradient.setColorAt(0, QColor(74, 144, 226, 200))
        gradient.setColorAt(1, QColor(74, 144, 226, 200))

        painter.fillRect(filled_rect, gradient)
        self.drawHandle(painter, self._low_value)
        self.drawHandle(painter, self._high_value)

    def drawHandle(self, painter, value):
        """Draw the handle at the given value"""
        handle_rect = QRect(0, 0, 16, 16)
        handle_rect.moveCenter(QPoint(self.valueToPixel(value), self.rect().center().y()))
        painter.setBrush(QColor(255, 255, 255))
        painter.setPen(QPen(QColor(74, 144, 226), 2))
        painter.drawEllipse(handle_rect)

    def valueToPixel(self, value):
        """Convert slider value to pixel position"""
        return int((value - self.minimum()) / (self.maximum() - self.minimum()) * self.width())

    def pixelToValue(self, pixel):
        """Convert pixel position to slider value"""
        return int(self.minimum() + (pixel / self.width()) * (self.maximum() - self.minimum()))

    def mousePressEvent(self, event):
        """Handle mouse press to move handles"""
        x = event.x()
        low_handle_pos = self.valueToPixel(self._low_value)
        high_handle_pos = self.valueToPixel(self._high_value)

        # Determine which handle is closer
        if abs(x - low_handle_pos) < abs(x - high_handle_pos):
            self._low_value = self.pixelToValue(x)
        else:
            self._high_value = self.pixelToValue(x)

        # Ensure correct order
        if self._low_value > self._high_value:
            self._low_value, self._high_value = self._high_value, self._low_value

        self.update()
        self.rangeChanged.emit(self._low_value, self._high_value)

    def mouseMoveEvent(self, event):
        """Handle mouse move to adjust handles"""
        if event.buttons() & Qt.LeftButton:
            x = event.x()
            low_handle_pos = self.valueToPixel(self._low_value)
            high_handle_pos = self.valueToPixel(self._high_value)

            # Determine which handle is closer
            if abs(x - low_handle_pos) < abs(x - high_handle_pos):
                self._low_value = self.pixelToValue(x)
            else:
                self._high_value = self.pixelToValue(x)

            # Ensure correct order
            if self._low_value > self._high_value:
                self._low_value, self._high_value = self._high_value, self._low_value

            self.update()
            self.rangeChanged.emit(self._low_value, self._high_value)
