# SPDX-FileCopyrightText: 2025 XLeitstelle Planen und Bauen <xleitstelle@gv.hamburg.de>
# SPDX-FileContributor: Tobias Kraft <tobias.kraft@gv.hamburg.de>
# SPDX-FileContributor: Anton Jacobsson <anton.jacobsson@init.de>
#
# SPDX-License-Identifier: EUPL-1.2
import logging
from typing import Callable, cast

from qgis.core import (
    Qgis,
    QgsApplication,
    QgsEditError,
    QgsFeature,
    QgsGeometry,
    QgsMapLayer,
    QgsProject,
    QgsVectorLayer,
    QgsVectorLayerUtils,
    edit,
)
from qgis.gui import (
    QgsAttributeEditorContext,
    QgsMapLayerAction,
    QgsMapLayerActionContext,
    QgsMapToolCapture,
)
from qgis.PyQt.QtCore import QObject, pyqtSlot
from qgis.utils import iface

from xmas_plugin.actions.common import GeometryCaptureTool
from xmas_plugin.plan_manager import PlanManager
from xmas_plugin.util.metadata import PLUGIN_DIR_NAME, PLUGIN_NAME

logger = logging.getLogger(PLUGIN_DIR_NAME)


class AddSection(QgsMapLayerAction):
    def __init__(
        self, get_plan_manager: Callable[[], PlanManager], parent: QObject | None = None
    ):
        super().__init__(
            "Bereich hinzufügen",
            parent,
            Qgis.MapLayerActionTarget.SingleFeature,
            QgsApplication.instance().getThemeIcon("mActionAddLayer.svg"),
            Qgis.MapLayerActionFlags(),
        )
        self._get_plan_manager = get_plan_manager
        self.current_tool = None
        self.dlg = None
        self.digit_tool = None
        self.layer = None
        self.plan = None
        self.triggeredForFeatureV2.connect(self._setup)

    def canRunUsingLayer(
        self,
        layer: QgsMapLayer | None,
        _: QgsMapLayerActionContext = QgsMapLayerActionContext(),
    ) -> bool:
        return (
            layer.customProperty(f"{PLUGIN_DIR_NAME}/layer_type") == "plan"
            and layer.customProperty(f"{PLUGIN_DIR_NAME}/appschema") in ["xplan", "xwp"]
            if layer
            else False
        )

    @pyqtSlot("QgsMapLayer*", QgsFeature, QgsMapLayerActionContext)
    def _setup(
        self,
        layer: QgsMapLayer,
        plan: QgsFeature,
        _: QgsMapLayerActionContext,
    ) -> None:
        canvas = iface.mapCanvas()

        if not layer:
            logger.debug(f"Layer: {layer} None, aborting add section.")
            return
        self.layer = cast(QgsVectorLayer, layer)

        if not plan:
            logger.debug(f"Plan: {plan} None, aborting add section.")
            return
        self.plan = plan

        self.current_tool = canvas.mapTool()

        self.digit_tool = GeometryCaptureTool(
            iface.mapCanvas(),
            iface.cadDockWidget(),
            QgsMapToolCapture.CaptureMode.CapturePolygon,
            self._handle_digitizing,
        )
        canvas.setMapTool(self.digit_tool)

        iface.messageBar().pushInfo(
            PLUGIN_NAME, "Geometrie für neuen Bereich erfassen oder weiter mit ESC"
        )

    @pyqtSlot(QgsGeometry)
    def _handle_digitizing(self, digit_feature: QgsGeometry | None) -> None:
        try:
            prefix = self.plan["featuretype"][:2]
            feature = QgsVectorLayerUtils.createFeature(
                self.layer,
                digit_feature if digit_feature is not None else QgsGeometry(),
                {self.layer.fields().indexFromName("featuretype"): f"{prefix}_Bereich"},
            )
            self.dlg = iface.getFeatureForm(self.layer, feature)
            self.dlg.setMode(QgsAttributeEditorContext.Mode.AddFeatureMode)

            try:
                if self.layer.isEditable():
                    accepted = self.dlg.exec()
                else:
                    with edit(self.layer):
                        accepted = self.dlg.exec()
            except QgsEditError as e:
                msg = "Fehler beim Speichern des Bereichs"
                iface.messageBar().pushCritical(PLUGIN_NAME, msg)
                QgsApplication.messageLog().logMessage(
                    f"{msg}: {e!r}",
                    PLUGIN_NAME,
                    Qgis.Critical,
                )
                return
            if accepted:
                feature = self.dlg.attributeForm().currentFormFeature()
                root = QgsProject.instance().layerTreeRoot()
                section_layers = []
                section_number = feature["properties"]["nummer"]
                self._get_plan_manager().build_section_group(
                    bereich={
                        "id": feature["id"],
                        "nummer": section_number,
                        "geometry": feature.hasGeometry(),
                    },
                    group=root.findLayer(self.layer).parent(),
                    layers=section_layers,
                    plan_id=self.plan["id"],
                    appschema=feature["appschema"],
                    version=feature["version"],
                )
                QgsProject.instance().addMapLayers(
                    section_layers,
                    False,
                )
                iface.messageBar().pushSuccess(
                    PLUGIN_NAME,
                    f"Bereich {section_number} hinzugefügt",
                )
        except Exception as e:
            msg = "Fehler beim Hinzufügen des Bereichs"
            iface.messageBar().pushCritical(PLUGIN_NAME, msg)
            QgsApplication.messageLog().logMessage(
                f"{msg}: {e!r}",
                PLUGIN_NAME,
                Qgis.Critical,
            )
        finally:
            self._cleanup()

    def _cleanup(self) -> None:
        if self.current_tool:
            iface.mapCanvas().setMapTool(self.current_tool)
            self.current_tool = None

        if self.digit_tool:
            self.digit_tool.deleteLater()
            self.digit_tool = None

        if self.dlg:
            self.dlg.deleteLater()
            self.dlg = None

        self.layer = None
        self.plan = None
