from PyQt5.QtWidgets import (
    QGraphicsScene, QGraphicsPixmapItem, QPushButton,
    QHBoxLayout, QVBoxLayout, QWidget, QSlider, QLabel
)
from PyQt5.QtGui import QFont, QPixmap
from PyQt5.QtCore import Qt, QRectF, QSize
from circleEditorGraphicsView import CircleEditorGraphicsView
from draggableCircleItem import DraggableCircleItem
from typing import Optional, Callable

class CircleEditorWidget(QWidget):
    """
    A widget for the user to calibrate the disk size (kernel size) for the ridge detection.
    """
    def __init__(self, pixmap: QPixmap, init_radius: int = 20, done_callback: Optional[Callable[[], None]] = None, parent: Optional[QWidget] = None):
        """
        Constructor.
        """
        super().__init__(parent)
        self._pixmap = pixmap
        self._done_callback = done_callback
        self._init_radius = init_radius

        layout = QVBoxLayout(self)
        self.setLayout(layout)

        # Add centered label above image
        label_instructions = QLabel("Scale the dot to be of the size of your ridge")
        label_instructions.setAlignment(Qt.AlignCenter)
        big_font = QFont("Arial", 20)
        big_font.setBold(True)
        label_instructions.setFont(big_font)
        layout.addWidget(label_instructions)

        # Show the image
        self._graphics_view = CircleEditorGraphicsView(circle_editor_widget=self)
        self._scene = QGraphicsScene(self)
        self._graphics_view.setScene(self._scene)
        layout.addWidget(self._graphics_view)

        self._image_item = QGraphicsPixmapItem(self._pixmap)
        self._scene.addItem(self._image_item)

        # Put circle in center
        cx = self._pixmap.width() / 2
        cy = self._pixmap.height() / 2
        self._circle_item = DraggableCircleItem(cx, cy, radius=self._init_radius, color=Qt.red)
        self._scene.addItem(self._circle_item)

        # Fit in view
        self._graphics_view.setSceneRect(QRectF(self._pixmap.rect()))
        self._graphics_view.fitInView(self._image_item, Qt.KeepAspectRatio)

        ### Controls below
        bottom_layout = QHBoxLayout()
        layout.addLayout(bottom_layout)

        # label + slider
        self._lbl_size = QLabel(f"size ({self._init_radius})")
        bottom_layout.addWidget(self._lbl_size)

        self._slider = QSlider(Qt.Horizontal)
        self._slider.setRange(1, 200)
        self._slider.setValue(self._init_radius)
        bottom_layout.addWidget(self._slider)

        # Done button
        self._btn_done = QPushButton("Done")
        bottom_layout.addWidget(self._btn_done)

        # Connect signals
        self._slider.valueChanged.connect(self._on_slider_changed)
        self._btn_done.clicked.connect(self._on_done_clicked)

    def _on_slider_changed(self, value: int):
        """
        Handle slider value changes.
        """
        self._circle_item.set_radius(value)
        self._lbl_size.setText(f"size ({value})")

    def _on_done_clicked(self):
        """
        Handle the user clicking the "Done" button.
        """
        final_radius = self._circle_item.radius()
        if self._done_callback is not None:
            self._done_callback(final_radius)

    def update_slider_value(self, new_radius: int):
        """
        Update the slider value.
        """
        self._slider.blockSignals(True)
        self._slider.setValue(new_radius)
        self._slider.blockSignals(False)
        self._lbl_size.setText(f"size ({new_radius})")

    def sizeHint(self):
        return QSize(800, 600)