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

from qgis.core import QgsCurvePolygon, QgsGeometry, QgsPointXY
from qgis.gui import QgsAdvancedDigitizingDockWidget, QgsMapCanvas, QgsMapToolCapture
from qgis.PyQt.QtCore import Qt

from xmas_plugin.util.metadata import PLUGIN_DIR_NAME

logger = logging.getLogger(PLUGIN_DIR_NAME)


class GeometryCaptureTool(QgsMapToolCapture):
    """Thin wrapper around QgsMapToolCapture for capturing geometries.

    Works around a QGIS bug where pointCaptured/geometryCaptured virtual
    methods are not called back from C++ in some versions.
    See: https://github.com/qgis/QGIS/issues/XXXXX (replace with actual issue if filed)
    """

    def __init__(
        self,
        canvas: QgsMapCanvas | None,
        cadDockWidget: QgsAdvancedDigitizingDockWidget | None,
        mode: QgsMapToolCapture.CaptureMode,
        handler: Callable[[QgsGeometry], None],
    ):
        super().__init__(canvas, cadDockWidget, mode)
        self._handler = handler
        self._handled = False

    def cadCanvasPressEvent(self, e) -> None:
        logger.debug("cadCanvasPressEvent fired")
        super().cadCanvasPressEvent(e)
        if self.mode() == QgsMapToolCapture.CaptureMode.CapturePoint:
            # Always handle point capture here as a fallback for QGIS versions
            # where pointCaptured is not called back from C++.
            if not self._handled:
                point = e.mapPoint()
                logger.debug(
                    "Handling point capture via cadCanvasPressEvent: %s", point
                )
                self._handled = True
                self._handler(QgsGeometry.fromPointXY(point))

    def cadCanvasReleaseEvent(self, e) -> None:
        logger.debug(
            "cadCanvasReleaseEvent fired, currentVectorLayer: %s",
            self.currentVectorLayer(),
        )

        if (
            self.mode() == QgsMapToolCapture.CaptureMode.CapturePolygon
            and e.button() == Qt.RightButton
            and not self._handled
        ):
            curve = self.captureCurve().clone()
            if curve.numPoints() >= 3:
                curve.close()
                polygon = QgsGeometry(QgsCurvePolygon())
                polygon.get().setExteriorRing(curve)
                logger.debug(
                    "Handling polygon capture via cadCanvasReleaseEvent: %s", polygon
                )
                self._handled = True
                self._handler(QgsGeometry(polygon))

        super().cadCanvasReleaseEvent(e)
        # Reset flag after the full cycle
        self._handled = False

    def pointCaptured(self, point) -> None:
        logger.debug("pointCaptured called with: %s", point)
        if not self._handled:
            self._handled = True
            self._handler(QgsGeometry.fromPointXY(QgsPointXY(point)))
        else:
            logger.debug(
                "pointCaptured skipped — already handled via cadCanvasPressEvent"
            )

    def geometryCaptured(self, geometry: QgsGeometry) -> None:
        logger.debug("geometryCaptured called with: %s", geometry)
        if not self._handled:
            self._handled = True
            self._handler(geometry)
        else:
            logger.debug("geometryCaptured skipped — already handled")

    def keyPressEvent(self, e) -> None:
        if e.key() == Qt.Key_Escape:
            logger.debug(
                "User pressed escape to _either_ save a section object without geometry _or_ aborting."
            )
            self._handler(None)
        else:
            super().keyPressEvent(e)
