########################################################################
## SPINN DESIGN CODE
# YOUTUBE: (SPINN TV) https://www.youtube.com/spinnTv
# WEBSITE: spinncode.com
########################################################################
from qtpy.QtCore import Qt, QEasingCurve, QPropertyAnimation, QSize, Property, QPoint, QEnum, QObject
from qtpy.QtGui import QPalette, QIcon, QPaintEvent, QPainter, QColor
from qtpy.QtWidgets import QCheckBox, QApplication, QLabel, QStyleOption, QStyle

import os

class QCustomCheckBox(QCheckBox):
    script_dir = os.path.dirname(os.path.realpath(__file__))
    WIDGET_ICON = os.path.join(script_dir, "components/icons/check_box.png")
    WIDGET_TOOLTIP = "A custom animated checkbox widget"
    WIDGET_DOM_XML = """
    <ui language='c++'>
        <widget class='QCustomCheckBox' name='customCheckBox'>
        </widget>
    </ui>
    """
    WIDGET_MODULE="Custom_Widgets.QCustomCheckBox"
    
    def __init__(self, parent=None):
        super().__init__(parent)

        self.setCursor(Qt.PointingHandCursor)

        # Check if a QApplication instance already exists
        if QApplication.instance():
            app = QApplication.instance()
        else:
            app = QApplication([])


        # Get the default palette
        palette = app.palette()
            
        # Get the default background color
        bgColor = palette.color(QPalette.Window)
        # Get the default text color (assuming this is your "circle_color")
        circleColor = palette.color(QPalette.Text)
        # Get the default highlight color (assuming this is your "active_color")
        activeColor = palette.color(QPalette.Highlight)

        # COLORS
        self.bgColor = bgColor
        self._circleColor = circleColor
        self._activeColor = activeColor

        # Animation
        self._animationEasingCurve = QEasingCurve.OutBounce
        self._easing_curve = 0
        self._animationDuration = 300

        self.pos = 0
        self.animation = QPropertyAnimation(self, b"position")
        self.animation.setEasingCurve(self._animationEasingCurve)
        self.animation.setDuration(self._animationDuration)
        self.stateChanged.connect(self.setup_animation)

        # Create a QLabel to display the text
        self.label = QLabel(self)
        # self.label.setContentsMargins(0, 0, 0, 0)  # Set contents margins to 0 to remove spacing
        self.label.setWordWrap(True)

        # Initialize icon
        self.icon = QIcon()
        self._iconSize = QSize(0, 0)  # Default icon size

    @Property(QColor)
    def backgroundColor(self):
        return self.bgColor
    
    @backgroundColor.setter
    def backgroundColor(self, color):
        self.bgColor = color
    
    @Property(QColor)
    def circleColor(self):
        return self._circleColor
    
    @circleColor.setter
    def circleColor(self, color):
        self._circleColor = color

    @Property(QColor)
    def activeColor(self):
        return self._activeColor
    
    @activeColor.setter
    def activeColor(self, color):
        self._activeColor = color

    @Property(int)
    def animationDuration(self):
        return self._animationDuration
    
    @animationDuration.setter
    def animationDuration(self, duration):
        self._animationDuration = duration

    @Property(QEasingCurve, designable=True)
    def animationEasingCurve(self):
        return self._easing_curve
    
    @animationEasingCurve.setter
    def animationEasingCurve(self, curve):
        # if not isinstance(curve, EasingCurveEnum):
        #     raise ValueError("Invalid easing curve enum")
            
        self._easing_curve = curve

    def setIcon(self, icon):
        self.icon = icon
        self.update()
    
    def setIconSize(self, size):
        """
        Set the size of the icon for the checkbox.

        Parameters:
            size (QSize): The size of the icon.
        """
        self._iconSize = size
        self.update()

    ########################################################################
    # Customize QCustomCheckBox
    ########################################################################
    def customizeQCustomCheckBox(self, **customValues):
        if "bgColor" in customValues:
            self.bgColor = customValues["bgColor"]
        
        if "circleColor" in customValues:
            self._circleColor = customValues["circleColor"]

        if "activeColor" in customValues:
            self._activeColor = customValues["activeColor"]

        if "animationEasingCurve" in customValues:
            self.animationEasingCurve = customValues["animationEasingCurve"]
            self.animation.setEasingCurve(self.animationEasingCurve)

        if "animationDuration" in customValues:
            self._animationDuration = customValues["animationDuration"]
            self.animation.setDuration(self._animationDuration)

        self.update()
    
    def showEvent(self, e):
        super().showEvent(e)
        self.adjustWidgetSize()
        self.update()


    def resizeEvent(self, event):
        super().resizeEvent(event)
        self.adjustWidgetSize()

    def adjustWidgetSize(self):
        # self.adjustSize()
        # Update checkbox size
        # Update label position and width
        icon_size = self._iconSize.width()
        label_margin = 5  # Adjust the margin between the icon and the label

        if not self.label.text().strip():
            self.label.setFixedSize(0, 0)
        else:
            label_width = self.width() - (self.height() * 2.1 + icon_size + label_margin)  # Calculate the width of the label area
            label_height = self.height()  # Use the height of the checkbox for the label height

            self.label.adjustSize()
            
            label_x = self.height() * 2.1 + icon_size + label_margin  # Calculate the x position of the label
            label_y = (self.height() - label_height) / 2  # Center the label vertically within the checkbox area

            self.label.setGeometry(label_x, label_y, label_width, label_height)
        
        self.update()


    def setText(self, text):
        # super().setText(text)
        self.label.setText(text)
        self.adjustWidgetSize()

    @Property(float, designable=False)
    def position(self):
        return self.pos
    
    @position.setter
    def position(self, pos):
        self.pos = pos
        self.update()

    # START STOP ANIMATION
    def setup_animation(self, value):
        self.pos = 0
        self.animation.stop()
        if value:
            self.animation.setEndValue(self.height() + 2)
        else:
            self.animation.setEndValue(0)
        self.animation.start()
    
    def hitButton(self, pos: QPoint):
        return self.contentsRect().contains(pos)

    def paintEvent(self, e: QPaintEvent):
        super().paintEvent(e)
     
        opt = QStyleOption()
        opt.initFrom(self)
        painter = QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        self.style().drawPrimitive(QStyle.PE_Widget, opt, painter, self)

        # SET PEN
        painter.setPen(Qt.NoPen)

        # Define margins
        margin = 3

        # DRAW ICON (Optional)
        if not self.icon.isNull():
            icon_size = self.height() * 0.7 if self.icon.availableSizes() else QSize(16, 16)  
            if self._iconSize == QSize(0, 0):
                self._iconSize = QSize(icon_size, icon_size)
            
            pixmap = self.icon.pixmap(self._iconSize)
            # Adjust horizontal position to add margin between checkbox and icon
            icon_x = self.height() * 2.1 + margin
            icon_y = (self.height() - self._iconSize.height()) / 2  # Center the icon vertically within the checkbox area
            painter.drawPixmap(icon_x, icon_y, pixmap)

        if not self.isChecked():
            # Draw rounded rectangle for unchecked state
            painter.setBrush(QColor(self.bgColor))
            painter.drawRoundedRect(0, 0, self.height() * 2.1, self.height(), self.height() * .5, self.height() * .5)

            # Draw circle for unchecked state
            painter.setBrush(QColor(self._circleColor))
            painter.drawEllipse(self.pos, 0, self.height(), self.height())
        else:
            # Draw rounded rectangle for checked state
            painter.setBrush(QColor(self._activeColor))
            painter.drawRoundedRect(0, 0, self.height() * 2.1, self.height(), self.height() * .5, self.height() * .5)

            # Draw circle for checked state
            painter.setBrush(QColor(self._circleColor))
            painter.drawEllipse(self.pos, 0, self.height(), self.height())
        
        self.adjustWidgetSize()

        painter.end()
        
