from __future__ import annotations

from bec_qthemes import material_icon
from qtpy.QtCore import QSize, Signal
from qtpy.QtWidgets import (
    QApplication,
    QFrame,
    QHBoxLayout,
    QLabel,
    QLayout,
    QSizePolicy,
    QToolButton,
    QVBoxLayout,
    QWidget,
)

from bec_widgets.utils.clickable_label import ClickableLabel
from bec_widgets.utils.error_popups import SafeProperty, SafeSlot


class ExpandableGroupFrame(QFrame):
    broadcast_size_hint = Signal(QSize)
    imminent_deletion = Signal()
    expansion_state_changed = Signal()

    EXPANDED_ICON_NAME: str = "collapse_all"
    COLLAPSED_ICON_NAME: str = "expand_all"

    def __init__(
        self, parent: QWidget | None = None, title: str = "", expanded: bool = True, icon: str = ""
    ) -> None:
        super().__init__(parent=parent)
        self._expanded = expanded

        self._title_text = f"<b>{title}</b>"
        self.setFrameStyle(QFrame.Shape.StyledPanel | QFrame.Shadow.Raised)
        self.setSizePolicy(QSizePolicy.Policy.Minimum, QSizePolicy.Policy.Minimum)
        self._layout = QVBoxLayout()
        self._layout.setContentsMargins(5, 0, 0, 0)
        self.setLayout(self._layout)

        self._create_title_layout(title, icon)

        self._contents = QWidget(self)
        self._layout.addWidget(self._contents)

        self._expansion_button.clicked.connect(self.switch_expanded_state)
        self.expanded = self._expanded  # type: ignore
        self.expansion_state_changed.emit()

    def _create_title_layout(self, title: str, icon: str):
        self._title_layout = QHBoxLayout()
        self._layout.addLayout(self._title_layout)
        self._internal_title_layout = QHBoxLayout()
        self._title_layout.addLayout(self._internal_title_layout)

        self._title = ClickableLabel()
        self._set_title_text(self._title_text)
        self._title_icon = ClickableLabel()
        self._internal_title_layout.addWidget(self._title_icon)
        self._internal_title_layout.addWidget(self._title)
        self.icon_name = icon
        self._title.clicked.connect(self.switch_expanded_state)
        self._title_icon.clicked.connect(self.switch_expanded_state)

        self._internal_title_layout.addStretch(1)

        self._expansion_button = QToolButton()
        self._update_expansion_icon()
        self._title_layout.addWidget(self._expansion_button, stretch=1)

    def get_title_layout(self) -> QHBoxLayout:
        return self._internal_title_layout

    def set_layout(self, layout: QLayout) -> None:
        self._contents.setLayout(layout)
        self._contents.layout().setContentsMargins(0, 0, 0, 0)  # type: ignore

    @SafeSlot()
    def switch_expanded_state(self):
        self.expanded = not self.expanded  # type: ignore
        self._update_expansion_icon()
        self.expansion_state_changed.emit()

    @SafeProperty(bool)
    def expanded(self):  # type: ignore
        return self._expanded

    @expanded.setter
    def expanded(self, expanded: bool):
        self._expanded = expanded
        self._contents.setVisible(expanded)
        self.updateGeometry()
        self.adjustSize()

    def _update_expansion_icon(self):
        self._expansion_button.setIcon(
            material_icon(icon_name=self.EXPANDED_ICON_NAME, size=(10, 10), convert_to_pixmap=False)
            if self.expanded
            else material_icon(
                icon_name=self.COLLAPSED_ICON_NAME, size=(10, 10), convert_to_pixmap=False
            )
        )

    @SafeProperty(str)
    def icon_name(self):  # type: ignore
        return self._title_icon_name

    @icon_name.setter
    def icon_name(self, icon_name: str):
        self._title_icon_name = icon_name
        self._set_title_icon(self._title_icon_name)

    def _set_title_icon(self, icon_name: str):
        if icon_name:
            self._title_icon.setVisible(True)
            self._title_icon.setPixmap(
                material_icon(icon_name=icon_name, size=(20, 20), convert_to_pixmap=True)
            )
        else:
            self._title_icon.setVisible(False)

    @SafeProperty(str)
    def title_text(self):  # type: ignore
        return self._title_text

    @title_text.setter
    def title_text(self, title_text: str):
        self._title_text = title_text
        self._set_title_text(self._title_text)

    def _set_title_text(self, title_text: str):
        self._title.setText(title_text)


# Application example
if __name__ == "__main__":  # pragma: no cover

    app = QApplication([])
    frame = ExpandableGroupFrame()
    layout = QVBoxLayout()
    frame.set_layout(layout)
    layout.addWidget(QLabel("test1"))
    layout.addWidget(QLabel("test2"))
    layout.addWidget(QLabel("test3"))

    frame.show()
    app.exec()
