from __future__ import annotations

from typing import TYPE_CHECKING, ClassVar

from qtpy.QtCore import QSize, Qt
from qtpy.QtGui import QStandardItem, QStandardItemModel
from qtpy.QtWidgets import QApplication, QListView, QVBoxLayout, QWidget

from utility.gui.qt.widgets.itemviews.abstractview import RobustAbstractItemView

if TYPE_CHECKING:
    from qtpy.QtWidgets import _QMenu


class RobustListView(RobustAbstractItemView, QListView):
    QT_WIDGET: ClassVar[type] = QListView

    def __new__(cls, *args, **kwargs):
        # For PySide6 compatibility with multiple inheritance
        return QListView.__new__(cls)

    def __init__(
        self,
        parent: QWidget | None = None,
        *args,
        should_call_qt_init: bool = True,
        **kwargs,
    ):
        if should_call_qt_init:
            QListView.__init__(self, parent, *args, **kwargs)
        RobustAbstractItemView.__init__(self, parent, *args, **kwargs)

    def build_context_menu(
        self,
        parent: QWidget | None = None,
    ) -> _QMenu:
        menu = super().build_context_menu(parent)

        list_menu = menu.addMenu("ListView")
        assert list_menu is not None
        settings_menu = list_menu.addMenu("Settings")
        assert settings_menu is not None
        actions_menu = list_menu.addMenu("Actions")
        assert actions_menu is not None

        self._add_exclusive_menu_action(
            settings_menu,
            "View Mode",
            self.viewMode,
            self.setViewMode,
            options={
                "List Mode": QListView.ViewMode.ListMode,
                "Icon Mode": QListView.ViewMode.IconMode
            },
            settings_key="viewMode"
        )

        self._add_menu_action(
            settings_menu,
            "Spacing",
            self.spacing,
            self.setSpacing,
            "spacing",
            param_type=int
        )
        self._add_menu_action(
            settings_menu,
            "Batch Size",
            self.batchSize,
            self.setBatchSize,
            "batchSize",
            param_type=int
        )
        self._add_exclusive_menu_action(
            settings_menu,
            "Layout Mode",
            self.layoutMode,
            self.setLayoutMode,
            options={
                "Single Pass": QListView.LayoutMode.SinglePass,
                "Batched": QListView.LayoutMode.Batched
            },
            settings_key="layoutMode"
        )
        self._add_menu_action(
            settings_menu,
            "Model Column",
            self.modelColumn,
            self.setModelColumn,
            "modelColumn",
            param_type=int
        )
        self._add_menu_action(
            settings_menu,
            "Uniform Item Sizes",
            self.uniformItemSizes,
            self.setUniformItemSizes,
            "uniformItemSizes"
        )
        self._add_menu_action(
            settings_menu,
            "Word Wrap",
            self.wordWrap,
            self.setWordWrap,
            "wordWrap"
        )
        self._add_menu_action(
            settings_menu,
            "Selection Rectangle Visible",
            self.isSelectionRectVisible,
            self.setSelectionRectVisible,
            "selectionRectVisible"
        )
        self._add_menu_action(
            settings_menu,
            "Item Alignment",
            self.itemAlignment,
            self.setItemAlignment,
            "itemAlignment",
            param_type=Qt.AlignmentFlag
        )
        self._add_exclusive_menu_action(
            settings_menu,
            "Flow",
            self.flow,
            self.setFlow,
            options={
                "Left to Right": QListView.Flow.LeftToRight,
                "Top to Bottom": QListView.Flow.TopToBottom
            },
            settings_key="flow"
        )
        self._add_menu_action(
            settings_menu,
            "Grid Size",
            self.gridSize,
            self.setGridSize,
            "gridSize",
            param_type=QSize
        )
        self._add_exclusive_menu_action(
            settings_menu,
            "Resize Mode",
            self.resizeMode,
            self.setResizeMode,
            options={
                "Fixed": QListView.ResizeMode.Fixed,
                "Adjust": QListView.ResizeMode.Adjust
            },
            settings_key="resizeMode"
        )
        self._add_exclusive_menu_action(
            settings_menu,
            "Movement",
            self.movement,
            self.setMovement,
            options={
                "Static": QListView.Movement.Static,
                "Free": QListView.Movement.Free,
                "Snap": QListView.Movement.Snap
            },
            settings_key="movement"
        )
        self._add_menu_action(
            settings_menu,
            "Wrapping",
            self.isWrapping,
            self.setWrapping,
            "wrapping"
        )

        self._add_simple_action(actions_menu, "Clear Selection", self.clearSelection)
        self._add_simple_action(actions_menu, "Select All", self.selectAll)
        self._add_simple_action(actions_menu, "Scroll to Top", lambda: self.scrollTo(self.model().index(0, 0), QListView.ScrollHint.PositionAtTop))  # pyright: ignore[reportOptionalMemberAccess]
        self._add_simple_action(actions_menu, "Scroll to Bottom", lambda: self.scrollTo(self.model().index(self.model().rowCount() - 1, 0), QListView.ScrollHint.PositionAtBottom))  # pyright: ignore[reportOptionalMemberAccess]
        self._add_simple_action(actions_menu, "Reset", self.reset)
        self._add_simple_action(actions_menu, "Clear Property Flags", self.clearPropertyFlags)
        self._add_simple_action(actions_menu, "Update Geometries", self.updateGeometries)

        row_visibility_menu = settings_menu.addMenu("Row Visibility")
        model = self.model()
        if model is not None:
            for row in range(model.rowCount()):
                self._add_menu_action(
                    row_visibility_menu,
                    f"Row {row}",
                    lambda r=row: self.isRowHidden(r),
                    lambda hide, r=row: self.setRowHidden(r, hide),
                    f"rowHidden_{row}"
                )

        return menu


if __name__ == "__main__":
    import sys
    app = QApplication(sys.argv)
    window = QWidget()
    layout = QVBoxLayout(window)
    list_view = RobustListView()
    layout.addWidget(list_view)

    model = QStandardItemModel()
    q_app_style = QApplication.style()
    assert q_app_style is not None
    standard_pixmaps = [
        q_app_style.standardIcon(getattr(q_app_style.StandardPixmap, attr))
        for attr in dir(q_app_style.StandardPixmap)
        if not attr.startswith("_") and attr not in (
            "as_integer_ratio",
            "bit_length",
            "conjugate",
            "denominator",
            "from_bytes",
            "imag",
            "numerator",
            "real",
            "to_bytes",
        )
    ]

    used_icons = standard_pixmaps

    for i, icon in enumerate(used_icons):
        item = QStandardItem(icon, f"Item {i}")
        model.appendRow(item)

    list_view.setModel(model)
    list_view.setViewMode(QListView.ViewMode.IconMode)
    list_view.setGridSize(QSize(100, 100))
    list_view.setResizeMode(QListView.ResizeMode.Adjust)

    window.resize(800, 600)
    window.show()
    sys.exit(app.exec())
