"""Adapter to extract geometries from QgsVectorLayer for SAM prompt building."""

from __future__ import annotations

from typing import TYPE_CHECKING

import structlog

if TYPE_CHECKING:  # pragma: no mutate
    from qgis.core import QgsGeometry, QgsVectorLayer

logger = structlog.get_logger(__name__)

# TODO: support selected features only via checkbox in dialog
#  (currently uses all features)


def _extract_points(geom: QgsGeometry, label: int) -> list[dict]:
    """Extract point dicts from a single- or multi-part point geometry."""
    if geom.isMultipart():
        return [
            {"type": "point", "coords": (pt.x(), pt.y()), "label": label}
            for pt in geom.asMultiPoint()
        ]
    point = geom.asPoint()
    return [{"type": "point", "coords": (point.x(), point.y()), "label": label}]


def _extract_polygons(geom: QgsGeometry) -> list[dict]:
    """Extract polygon bbox dicts from a single- or multi-part polygon geometry."""
    parts = geom.asGeometryCollection() if geom.isMultipart() else [geom]
    return [
        {
            "type": "polygon",
            "bbox": (bb.xMinimum(), bb.yMinimum(), bb.xMaximum(), bb.yMaximum()),
        }
        for bb in (p.boundingBox() for p in parts)
    ]


def extract_geometries(vector_layer: QgsVectorLayer, target_crs: str) -> list[dict]:
    """Extract point/polygon geometries from a vector layer, reprojected to target_crs.

    Args:
        vector_layer: QgsVectorLayer to read features from.
        target_crs: CRS authority string (e.g. "EPSG:3857") to reproject
            geometries into.

    Returns:
        List of dicts: {"type": "point", "coords": (x, y)} or
                       {"type": "polygon", "bbox": (xmin, ymin, xmax, ymax)}
    """
    from qgis.core import (
        QgsCoordinateReferenceSystem,
        QgsCoordinateTransform,
        QgsProject,
        QgsWkbTypes,
    )

    source_crs = vector_layer.crs()
    dest_crs = QgsCoordinateReferenceSystem(target_crs)
    transform = QgsCoordinateTransform(source_crs, dest_crs, QgsProject.instance())
    need_transform = source_crs != dest_crs

    label_idx = vector_layer.fields().indexOf("label")
    if label_idx >= 0:  # pragma: no mutate (logging-only branch)
        logger.debug(f"Found 'label' field at index {label_idx}")
    else:
        logger.debug(
            "Layer '%s' has no 'label' field — all points default to foreground (1). "
            "Add an integer 'label' field (1=foreground, 0=background) to control "
            "FG/BG.",
            vector_layer.name(),
        )

    geometries = []
    for feature in vector_layer.getFeatures():  # pyright: ignore[reportGeneralTypeIssues]
        geom = feature.geometry()
        if geom.isNull():
            continue

        if need_transform:
            geom.transform(transform)

        label = int(feature["label"]) if label_idx >= 0 else 1
        geom_type = QgsWkbTypes.geometryType(geom.wkbType())

        if geom_type == QgsWkbTypes.PointGeometry:
            geometries.extend(_extract_points(geom, label))
        elif geom_type == QgsWkbTypes.PolygonGeometry:
            geometries.extend(_extract_polygons(geom))
        elif (
            geom_type == QgsWkbTypes.LineGeometry
        ):  # pragma: no mutate (both branches log+skip)
            logger.warning(f"Skipping line geometry in feature {feature.id()}")
        else:
            logger.warning(f"Skipping unknown geometry type in feature {feature.id()}")

    logger.debug(
        "extract_geometries: layer=%s, crs=%s -> target_crs=%s, "
        "features=%d, geometries=%d, result=%s",
        vector_layer.name(),
        vector_layer.crs().authid(),
        target_crs,
        vector_layer.featureCount(),
        len(geometries),
        geometries,
    )
    return geometries
