from enum import StrEnum

from geojson_pydantic.geometries import Geometry
from pydantic import BaseModel, Field

from olmoearth_shared.api.common.search_filters import DatetimeFilter, KeywordFilter, NumericFilter, SortDirection
from olmoearth_shared.models.datasets.collection import Collection
from olmoearth_shared.models.datasets.instrument_mode import InstrumentMode
from olmoearth_shared.models.datasets.item import Item
from olmoearth_shared.models.datasets.landsat_collection_category import LandsatCollectionCategory
from olmoearth_shared.models.datasets.orbit_direction import OrbitDirection
from olmoearth_shared.models.datasets.polarization import Polarization
from olmoearth_shared.models.datasets.satellite import Satellite


class ItemSortField(StrEnum):
    """Valid fields for sorting items in search results"""

    ID = "id"
    CREATED_AT = "created_at"
    UPDATED_AT = "updated_at"
    COLLECTED_AT = "collected_at"
    CLOUD_COVER = "cloud_cover"


class SearchItemsRequest(BaseModel):
    """Request model for searching items"""

    id: KeywordFilter[str] | None = Field(default=None, description="Filter by item ID")
    created_at: DatetimeFilter | None = Field(default=None, description="Filter by item creation time")
    updated_at: DatetimeFilter | None = Field(default=None, description="Filter by item last update time")
    collected_at: DatetimeFilter | None = Field(default=None, description="Filter by collection time (all collections)")
    intersects_geometry: Geometry | None = Field(default=None, description="Find items whose geometry intersects with this geometry")
    satellite: KeywordFilter[Satellite] | None = Field(default=None, description="Filter by satellite (all collections)")
    collection: KeywordFilter[Collection] | None = Field(default=None, description="Filter by collection")
    cloud_cover: NumericFilter | None = Field(default=None, description="Filter by cloud cover percentage (Sentinel-2, Landsat)")
    mgrs_tile: KeywordFilter[str] | None = Field(default=None, description="Filter by MGRS tile identifier (Sentinel-2)")
    wrs_path: NumericFilter | None = Field(default=None, description="Filter by WRS-2 path (Landsat)")
    wrs_row: NumericFilter | None = Field(default=None, description="Filter by WRS-2 row (Landsat)")
    collection_category: KeywordFilter[LandsatCollectionCategory] | None = Field(default=None, description="Filter by collection category (Landsat)")
    orbit_direction: KeywordFilter[OrbitDirection] | None = Field(default=None, description="Filter by orbit direction (Sentinel-1)")
    relative_orbit: NumericFilter | None = Field(default=None, description="Filter by relative orbit number (Sentinel-1, Sentinel-2)")
    instrument_mode: KeywordFilter[InstrumentMode] | None = Field(default=None, description="Filter by SAR instrument mode (Sentinel-1)")
    polarization: KeywordFilter[Polarization] | None = Field(default=None, description="Filter by polarization (Sentinel-1)")

    # Pagination and sorting
    limit: int = Field(default=50, ge=1, le=1000, description="Maximum number of results to return")
    offset: int = Field(default=0, ge=0, description="Number of results to skip")
    sort_by: ItemSortField = Field(default=ItemSortField.COLLECTED_AT, description="Field to sort by")
    sort_direction: SortDirection = Field(default=SortDirection.DESC, description="Sort direction")

    # Response options
    sign_urls: bool = Field(
        default=False,
        description=(
            "Sign asset URLs with temporary access tokens for direct download. "
            "Signed URLs expire after a short period (e.g. ~1 hour) and should not be cached. "
            "Only affects data providers that require signing (e.g., Planetary Computer)."
        ),
    )


class SearchItemsResponse(BaseModel):
    """Response model for searching items"""

    items: list[Item] = Field(description="List of items matching the search criteria")
    total: int = Field(description="Total number of items matching the search criteria")
    limit: int = Field(description="Maximum number of results returned")
    offset: int = Field(description="Number of results skipped")
