import sys
from pyqt_compat.QtCore import Qt, QSize, QRectF, pyqtProperty, QPropertyAnimation
from pyqt_compat.QtGui import QPainter, QColor, QBrush
from pyqt_compat.QtWidgets import QApplication, QWidget, QCheckBox, QHBoxLayout, QLabel


class AnimatedToggle(QCheckBox):
    def __init__(self, text="", parent=None):
        super().__init__(text, parent)  # Pass text to QCheckBox
        self.setCursor(Qt.CursorShape.PointingHandCursor)

        # Geometry
        self._thumb_radius = 10
        self._track_radius = 12
        self._margin = 3
        self._offset = 1.0 if self.isChecked() else 0.0

        # Ensure clickable size
        self.setMinimumSize(60, 30)

        # Animation
        self._animation = QPropertyAnimation(self, b"offset", self)
        self._animation.setDuration(200)
        self.stateChanged.connect(self.start_animation)

    def sizeHint(self):
        # Let QCheckBox handle text width + our switch size
        base = super().sizeHint()
        return QSize(max(base.width(), 60), max(base.height(), 30))

    def hitButton(self, pos):
        return self.rect().contains(pos)

    def get_offset(self):
        return self._offset

    def set_offset(self, value):
        self._offset = value
        self.update()

    offset = pyqtProperty(float, fget=get_offset, fset=set_offset)

    def start_animation(self, state):
        self._animation.stop()
        self._animation.setEndValue(1.0 if state == Qt.CheckState.Checked.value else 0.0)
        self._animation.start()

    def paintEvent(self, event):
        # Let QCheckBox handle text layout
        painter = QPainter(self)
        painter.setRenderHint(QPainter.RenderHint.Antialiasing)

        # Get the rectangle for the switch (excluding text)
        text_rect = self.style().subElementRect(
            self.style().SubElement.SE_CheckBoxContents, self.styleOption()
        )

        # Draw switch to the left of text
        switch_rect = QRectF(
            self._margin,
            (self.height() - (self._track_radius * 2)) / 2,
            50 - 2 * self._margin,
            self._track_radius * 2
        )

        # Track color
        track_color = QColor("#00C853") if self.isChecked() else QColor("#9E9E9E")
        painter.setBrush(QBrush(track_color))
        painter.setPen(Qt.PenStyle.NoPen)
        painter.drawRoundedRect(switch_rect, self._track_radius, self._track_radius)

        # Thumb position
        thumb_diameter = self._thumb_radius * 2
        thumb_x = switch_rect.left() + self._offset * (switch_rect.width() - thumb_diameter)
        thumb_rect = QRectF(
            thumb_x,
            switch_rect.center().y() - self._thumb_radius,
            thumb_diameter,
            thumb_diameter
        )

        painter.setBrush(QBrush(QColor("#FFFFFF")))
        painter.drawEllipse(thumb_rect)

        # Draw the label text
        painter.setPen(QColor("#000000"))
        painter.drawText(
            60,  # start after switch
            0,
            self.width() - 60,
            self.height(),
            Qt.AlignmentFlag.AlignVCenter | Qt.AlignmentFlag.AlignLeft,
            self.text()
        )

    def styleOption(self):
        """Helper to get QStyleOption for text layout."""
        from PyQt6.QtWidgets import QStyleOptionButton
        opt = QStyleOptionButton()
        self.initStyleOption(opt)
        return opt




class DemoWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("Animated PyQt6 Toggle Switch")
        self.resize(300, 100)

        layout = QHBoxLayout()

        self.label = QLabel("Switch is OFF")
        self.toggle = AnimatedToggle()
        self.toggle.stateChanged.connect(self.on_toggle)

        layout.addWidget(self.toggle)
        layout.addWidget(self.label)
        self.setLayout(layout)

    def on_toggle(self, state):
        if state == Qt.CheckState.Checked.value:
            self.label.setText("Switch is ON")
        else:
            self.label.setText("Switch is OFF")


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = DemoWindow()
    window.show()
    sys.exit(app.exec())
