"""Legacy STAC engine using stac-geoparquet library.

This module provides the stac-geoparquet engine implementation using the
pure Python stac-geoparquet library for STAC item conversion and GeoParquet I/O.

This engine is provided for backward compatibility and as a fallback when
rustac is not available.

Requirements:
    - stac-geoparquet>=0.2.0

Example:
    >>> from earthcatalog.engines.stac_geoparquet_engine import StacGeoparquetEngine
    >>> engine = StacGeoparquetEngine()
    >>> gdf = engine.items_to_geodataframe(items)
    >>> engine.write_geoparquet_sync(gdf, "output.parquet", storage)
"""

import logging
from typing import Any

import geopandas as gpd

from . import GeoParquetIOMixin, STACEngine

logger = logging.getLogger(__name__)

# Import stac_geoparquet - will raise ImportError if not available
try:
    from stac_geoparquet import to_geodataframe, to_item_collection

    HAS_STAC_GEOPARQUET = True
except ImportError:
    HAS_STAC_GEOPARQUET = False
    to_geodataframe = None  # type: ignore
    to_item_collection = None  # type: ignore


class StacGeoparquetEngine(GeoParquetIOMixin, STACEngine):
    """Legacy STAC engine using stac-geoparquet library.

    This engine uses the stac-geoparquet library for STAC item conversion.
    It provides a stable fallback option when rustac is not available.

    GeoParquet I/O operations are inherited from GeoParquetIOMixin to ensure
    consistent behavior across all engine implementations.

    Attributes:
        name: Engine identifier string ("stac-geoparquet").

    Example:
        >>> engine = StacGeoparquetEngine()
        >>> items = [{"type": "Feature", "id": "item1", ...}]
        >>> gdf = engine.items_to_geodataframe(items)
        >>> items_out = engine.geodataframe_to_items(gdf)
    """

    def __init__(self) -> None:
        """Initialize the stac-geoparquet engine.

        Raises:
            ImportError: If stac-geoparquet library is not installed.
        """
        if not HAS_STAC_GEOPARQUET:
            raise ImportError("stac-geoparquet library not available. Install with: pip install stac-geoparquet")

    @property
    def name(self) -> str:
        """Return the engine name."""
        return "stac-geoparquet"

    def items_to_geodataframe(self, items: list[dict[str, Any]]) -> gpd.GeoDataFrame:
        """Convert STAC items to GeoDataFrame using stac_geoparquet.to_geodataframe().

        Args:
            items: List of STAC item dictionaries.

        Returns:
            GeoDataFrame with geometry and all STAC properties.

        Raises:
            ValueError: If items cannot be converted.
        """
        if not items:
            return gpd.GeoDataFrame()

        try:
            # Use numpy_nullable to maintain current behavior and avoid FutureWarning
            gdf = to_geodataframe(items, dtype_backend="numpy_nullable")  # type: ignore[misc]
            return gdf

        except Exception as e:
            logger.error(f"Error converting items to GeoDataFrame with stac-geoparquet: {e}")
            raise ValueError(f"Failed to convert STAC items to GeoDataFrame: {e}") from e

    def geodataframe_to_items(self, gdf: gpd.GeoDataFrame) -> list[dict[str, Any]]:
        """Convert GeoDataFrame back to STAC items using stac_geoparquet.to_item_collection().

        Args:
            gdf: GeoDataFrame containing STAC item data.

        Returns:
            List of STAC item dictionaries.

        Raises:
            ValueError: If GeoDataFrame cannot be converted.
        """
        if gdf.empty:
            return []

        try:
            item_collection = to_item_collection(gdf)  # type: ignore[misc]

            # Handle both dict and FeatureCollection objects
            if hasattr(item_collection, "to_dict"):
                features = item_collection.to_dict().get("features", [])
            elif isinstance(item_collection, dict):
                features = item_collection.get("features", [])
            else:
                features = []

            return features

        except Exception as e:
            logger.error(f"Error converting GeoDataFrame to items with stac-geoparquet: {e}")
            raise ValueError(f"Failed to convert GeoDataFrame to STAC items: {e}") from e
