"""GDAL-based vectorizer implementing VectorizerPort for QGIS environment."""

import json

import structlog
from numpy import ndarray
from osgeo import gdal, ogr, osr

from samgis_core.geo.ports import VectorizerPort

logger = structlog.get_logger(__name__)


class GdalVectorizer(VectorizerPort):
    """Converts a binary mask + affine transform into GeoJSON using GDAL/OGR."""

    def __init__(self) -> None:
        self.n_shapes = 0

    def vectorize(
        self,
        mask: ndarray,
        transform: tuple[float, ...],
        source_crs: str = "EPSG:3857",
        target_crs: str = "EPSG:4326",
    ) -> str:
        h, w = mask.shape[:2]
        logger.debug(
            "vectorize: mask=%dx%d, source_crs=%s, target_crs=%s, transform=%s",
            w,
            h,
            source_crs,
            target_crs,
            transform,
        )

        # 1. Create in-memory GDAL raster from mask
        mem_drv = gdal.GetDriverByName("MEM")
        ds = mem_drv.Create(
            "", w, h, 1, gdal.GDT_Byte
        )  # pragma: no mutate (Polygonize uses band 1 only)
        ds.SetGeoTransform(transform)
        band = ds.GetRasterBand(1)
        band.WriteArray(mask if mask.ndim == 2 else mask[:, :, 0])

        # 2. Create in-memory OGR layer for polygons
        ogr_drv = ogr.GetDriverByName("Memory")
        ogr_ds = ogr_drv.CreateDataSource("")
        source_srs = osr.SpatialReference()
        source_srs.SetFromUserInput(source_crs)
        ogr_layer = ogr_ds.CreateLayer(
            "polygons", srs=source_srs, geom_type=ogr.wkbPolygon
        )
        field_defn = ogr.FieldDefn("raster_val", ogr.OFTInteger)
        ogr_layer.CreateField(field_defn)

        # 3. Polygonize
        gdal.Polygonize(band, None, ogr_layer, 0)

        # 4. Reproject if needed
        need_reproject = source_crs != target_crs
        coord_transform = None
        if need_reproject:
            target_srs = osr.SpatialReference()
            target_srs.SetFromUserInput(target_crs)
            coord_transform = osr.CoordinateTransformation(source_srs, target_srs)

        # 5. Build GeoJSON FeatureCollection
        features = []
        ogr_layer.ResetReading()
        feature = ogr_layer.GetNextFeature()
        while feature is not None:
            geom = feature.GetGeometryRef()
            if geom is not None:
                if need_reproject:
                    geom.Transform(coord_transform)
                geom_json = json.loads(geom.ExportToJson())
                feat = {
                    "type": "Feature",
                    "properties": {"raster_val": feature.GetField("raster_val")},
                    "geometry": geom_json,
                }
                features.append(feat)
            feature = ogr_layer.GetNextFeature()

        self.n_shapes = len(features)
        logger.debug(
            "vectorize: produced %d features, need_reproject=%s",
            self.n_shapes,
            need_reproject,
        )

        # Cleanup
        ds = None
        ogr_ds = None

        return json.dumps({"type": "FeatureCollection", "features": features})
