# SPDX-FileCopyrightText: 2025 XLeitstelle Planen und Bauen <xleitstelle@gv.hamburg.de>
# SPDX-FileContributor: Michael Holzapfel <michael.holzapfel@geocledian.com>
#
# SPDX-License-Identifier: EUPL-1.2-or-later

import logging
from typing import Any, List, Optional

from qgis.core import (
    QgsFeature,
    QgsGeometry,
    QgsProject,
    QgsVectorLayer,
    QgsRectangle,
)
from qgis.gui import QgisInterface
from qgis.PyQt.QtCore import (
    QAbstractTableModel,
    QModelIndex,
    QSortFilterProxyModel,
    Qt,
    QVariant,
)

from qgis.utils import iface
from xmas_plugin.topo_check import TopoTableView
from xmas_plugin.util.geom import transform_to_project_crs
from xmas_plugin.util.metadata import PLUGIN_DIR_NAME

logger = logging.getLogger(PLUGIN_DIR_NAME)


class OverlapTableModel(QAbstractTableModel):
    def __init__(
        self,
        data: List[QgsFeature | QgsVectorLayer],
        columns: List[str],
        parent: Optional[Any] = None,
    ) -> None:
        super().__init__(parent)
        self._data = data
        self._columns = columns

    def rowCount(self, parent: QModelIndex = QModelIndex()) -> int:
        return len(self._data)

    def columnCount(self, parent: QModelIndex = QModelIndex()) -> int:
        return len(self._columns)

    def data(self, index: QModelIndex, role: int = Qt.DisplayRole) -> Any:
        if index.isValid() and role == Qt.UserRole:
            return self._data[index.row()][index.column()]
        if not index.isValid() or role != Qt.DisplayRole:
            return QVariant()
        row = self._data[index.row()]
        item = row[index.column()]
        if index.column() == 0:
            return f"{self._data[index.row()][0].area():0.2f} m²"
        if isinstance(item, QgsFeature):
            item: QgsFeature
            return item.attribute("id")
        elif isinstance(item, QgsVectorLayer):
            item: QgsVectorLayer
            try:
                return item.name()
            except RuntimeError as e:
                logger.debug(f"qgsvector layer probably removed: {e}")
                return QVariant()
        else:
            return QVariant()

    def headerData(
        self, section: int, orientation: Qt.Orientation, role: int = Qt.DisplayRole
    ) -> Any:
        if role != Qt.DisplayRole:
            return QVariant()
        if orientation == Qt.Horizontal:
            return self._columns[section]
        return section + 1

    def repopulate(self, new_data) -> None:
        # Notify views that model is about to reset
        self.beginResetModel()
        self._data = new_data
        # Notify views that model reset is done
        self.endResetModel()


class OverlapTableView(TopoTableView):
    def __init__(self, iface: QgisInterface, parent=None):
        super().__init__(parent)
        self.iface = iface

        self.model = OverlapTableModel(
            data=[], columns=["Fläche", "Feature1", "Layer1", "Feature2", "Layer2"]
        )
        self.proxymodel = QSortFilterProxyModel()
        self.proxymodel.setSourceModel(self.model)
        self.setModel(self.proxymodel)
        self.setSortingEnabled(True)

        self.clicked.connect(self.on_click)
        self.proxymodel.modelReset.connect(self.resizeColumnsToContents)

    def on_click(self, index: QModelIndex) -> None:
        def _select_layer(layer: QgsVectorLayer) -> None:
            """
            Highlights/selects a layer in the QGis Layers Dock,
            if the layer is part of a (nested) group QGis should expand
            thos groups automatically
            :param layer:
            :return:
            """
            if not layer:
                return

            root = QgsProject.instance().layerTreeRoot()
            layer_node = root.findLayer(layer.id())
            if layer_node is None:
                return

            self.iface.layerTreeView().setCurrentLayer(layer)
            return

        src_index: QModelIndex = index.model().mapToSource(index)
        item: QgsGeometry | QgsFeature = self.model.data(src_index, Qt.UserRole)

        # select clicked layer in qgis layertree view
        if index.column() in [2, 4]:
            _select_layer(item)
            return

        if isinstance(item, QgsFeature):  # click on feature column
            _geom = item.geometry()
        elif isinstance(item, QgsGeometry):  # click on overlap-geom column
            _geom = item

        geom = transform_to_project_crs(_geom, self.plan_crs)
        _extent = geom.boundingBox()
        buffer_percentage = 0.4
        width = _extent.xMaximum() - _extent.xMinimum()
        height = _extent.yMaximum() - _extent.yMinimum()
        extent = QgsRectangle(
            _extent.xMinimum() - buffer_percentage * width,
            _extent.yMinimum() - buffer_percentage * height,
            _extent.xMaximum() + buffer_percentage * width,
            _extent.yMaximum() + buffer_percentage * height
        )

        # flash geometry
        iface.mapCanvas().flashGeometries([geom], crs=self.plan_crs,
                                          flashes=5, duration=500)
        iface.mapCanvas().flashGeometries([QgsGeometry(x) for x in geom.vertices()], crs=self.plan_crs,
                                          flashes=5, duration=500)

        # zoom to geometry
        canvas = self.iface.mapCanvas()
        canvas.setExtent(extent)
        canvas.refresh()

    def repopulate(self, new_data) -> None:
        self.model.repopulate(new_data)
