# SPDX-FileCopyrightText: 2025 XLeitstelle Planen und Bauen <xleitstelle@gv.hamburg.de>
# SPDX-FileContributor: Tobias Kraft <tobias.kraft@gv.hamburg.de>
#
# SPDX-License-Identifier: EUPL-1.2

from qgis.core import (
    Qgis,
    QgsApplication,
    QgsFeature,
    QgsMapLayer,
)
from qgis.gui import (
    QgsMapLayerAction,
    QgsMapLayerActionContext,
)
from qgis.PyQt.QtCore import QObject, pyqtSlot
from qgis.utils import iface

from xmas_plugin.util.metadata import PLUGIN_DIR_NAME, PLUGIN_NAME


class ForceCCW(QgsMapLayerAction):
    def __init__(self, parent: QObject | None = None):
        super().__init__(
            "CCW-Orientierung herstellen",
            parent,
            Qgis.MapLayerActionTargets(
                Qgis.MapLayerActionTarget.SingleFeature
                | Qgis.MapLayerActionTarget.MultipleFeatures
            ),
            QgsApplication.instance().getThemeIcon("mActionTiltUp.svg"),
            Qgis.MapLayerActionFlags(),
        )
        self._running = False
        self.triggeredForFeatureV2.connect(self._trigger_for_feature)
        self.triggeredForFeaturesV2.connect(self._trigger_for_features)

    def canRunUsingLayer(
        self,
        layer: QgsMapLayer | None,
        _: QgsMapLayerActionContext = QgsMapLayerActionContext(),
    ) -> bool:
        return (
            layer.customProperty(f"{PLUGIN_DIR_NAME}/layer_type") is not None
            and layer.geometryType().name == "Polygon"
            and layer.isEditable()
            if layer
            else False
        )

    @pyqtSlot("QgsMapLayer*", QgsFeature, QgsMapLayerActionContext)
    def _trigger_for_feature(
        self,
        layer: QgsMapLayer,
        feature: QgsFeature,
        _: QgsMapLayerActionContext,
    ) -> None:
        self._force_ccw(layer, [feature])

    @pyqtSlot("QgsMapLayer*", "QList<QgsFeature>", QgsMapLayerActionContext)
    def _trigger_for_features(
        self,
        layer: QgsMapLayer,
        features: list[QgsFeature],
        _: QgsMapLayerActionContext,
    ) -> None:
        self._force_ccw(layer, features)

    def _force_ccw(
        self,
        layer: QgsMapLayer,
        features: list[QgsFeature],
    ) -> None:
        has_curves = []
        for feature in features:
            geom = feature.geometry()
            abs_geom = geom.constGet()
            if abs_geom.hasCurvedSegments():
                has_curves.append(feature.attributeMap().get("id", "unknown"))
        if len(has_curves) > 0:
            iface.messageBar().pushWarning(
                PLUGIN_NAME,
                f"Geometrien enthalten Kurven und können nicht neu orientiert werden. Weitere Details "
                f'finden Sie im Bedienfeld "Protokoll"→"{PLUGIN_NAME}"',
            )
            QgsApplication.messageLog().logMessage(
                f"folgende Features enthalten Kurven und können nicht neu orientiert werden:"
                f"\n{','.join(has_curves)}\nZur Umwandlung dieser Geometrien können Sie das Werkzeug"
                f' "Kurven" aus der Topologie Prüfung benutzen (alternativ: '
                f'"Verarbeitungswerkzeuge"→"Vektorgeometrie"→"Durch maximalen Abstand segmentieren")',
                PLUGIN_NAME,
                Qgis.Warning,
            )
            return

        if not any(feature.geometry().isPolygonClockwise() for feature in features):
            iface.messageBar().pushInfo(
                PLUGIN_NAME,
                "Feature-Geometrie(n) bereits CCW-orientiert.",
            )
            return
        edited = 0
        layer.beginEditCommand("force polygon CCW")
        try:
            for feature in features:
                if feature.geometry().isPolygonClockwise():
                    layer.changeGeometry(
                        feature.id(), feature.geometry().forcePolygonCounterClockwise()
                    )
                    edited += 1
        finally:
            layer.endEditCommand()
        iface.messageBar().pushSuccess(
            PLUGIN_NAME,
            f"Geometrie-Orientierung für {edited} Feature(s) in CCW geändert.",
        )
