# 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
import re
from typing import List

from qgis._core import QgsLayerTreeGroup, QgsMapLayer, QgsProject
from qgis.core import QgsCoordinateReferenceSystem, QgsVectorLayer
from qgis.PyQt.QtWidgets import QHeaderView, QTableView
from qgis.utils import iface


class TopoTableView(QTableView):
    """
    Base Class for TableViews
    """

    def __init__(self, parent=None):
        super().__init__(parent)

        # placeholder for CRS
        self.plan_crs: QgsCoordinateReferenceSystem | None = None
        self.verticalHeader().setVisible(False)

        # self.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
        # self.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
        self.horizontalHeader().setSectionResizeMode(QHeaderView.Interactive)
        self.horizontalHeader().setStretchLastSection(True)

        # slug used in subsetfiltering layers
        self.subset_slug = "topotable filter"
        # strings used to construct and remove subset-filters on layers
        self.subset_start_token = f"/* {self.subset_slug} start */"
        self.subset_end_token = f"/* {self.subset_slug} end */"

    def clear_subset_filters(self) -> None:
        """
        reset all layer subsetfilters
        :param self:
        :return:
        """
        # no current plan available -> remove subset filters for all plans/layers in project
        if not self.plan_id:
            for layer in QgsProject.instance().mapLayers().values():
                if isinstance(layer, QgsVectorLayer):
                    if layer.customProperties().contains("xmas_plugin/plan_id"):
                        current_subsetstr = layer.dataProvider().subsetString()
                        if self.subset_slug in current_subsetstr:
                            unfiltered_subsetstr = re.sub(
                                pattern=rf" {re.escape(self.subset_start_token)}.*?"
                                rf"{re.escape(self.subset_end_token)}",
                                repl="",
                                string=current_subsetstr,
                                flags=re.DOTALL,
                            )
                            layer.dataProvider().setSubsetString(
                                unfiltered_subsetstr, True
                            )
                            layer.triggerRepaint()
            return

        # current plan available -> remove subset filters for current plan layers only
        for layer in QgsProject.instance().mapLayers().values():
            if isinstance(layer, QgsVectorLayer):
                if (
                    layer.customProperties().value("xmas_plugin/plan_id")
                    == self.plan_id
                ):
                    current_subsetstr = layer.dataProvider().subsetString()
                    if self.subset_slug in current_subsetstr:
                        unfiltered_subsetstr = re.sub(
                            pattern=rf" {re.escape(self.subset_start_token)}.*?"
                            rf"{re.escape(self.subset_end_token)}",
                            repl="",
                            string=current_subsetstr,
                            flags=re.DOTALL,
                        )
                        layer.dataProvider().setSubsetString(unfiltered_subsetstr, True)
                        layer.triggerRepaint()

        # show all layers of plan
        for layer in QgsProject.instance().mapLayers().values():
            if layer.customProperties().value("xmas_plugin/plan_id") == self.plan_id:
                layer_node = QgsProject.instance().layerTreeRoot().findLayer(layer.id())
                if layer_node:
                    layer_node.setItemVisibilityChecked(True)

        # clear layer tree selection
        view = iface.layerTreeView()
        view.clearSelection()


def get_layer_group_hierarchy(vector_layer: QgsMapLayer) -> List[QgsLayerTreeGroup]:
    """
    Return the hierarchy of groups that the given vector layer belongs to.
    :param vector_layer: QgsMapLayer, The layer whose groups should be retrieved.
    :return: list[QgsLayerTreeGroup], Ordered list of groupsfrom the top‑most group down to the immediate parent of the layer.
             If the layer is not inside any group, an empty list is returned.
    """

    root = QgsProject.instance().layerTreeRoot()
    layer_node = root.findLayer(vector_layer.id())

    if layer_node is None:
        raise ValueError("Layer not found in the current QGIS project.")

    # walk down tree, collect group names
    groups = []
    parent = layer_node.parent()
    while isinstance(parent, QgsLayerTreeGroup):
        # skip root node
        if parent != root:
            groups.append(parent)
        parent = parent.parent()

    # reverse group list, outer/top group first
    groups.reverse()
    return groups
