from __future__ import annotations from datetime import datetime from typing import Literal from uuid import UUID from pydantic import BaseModel, model_validator from app.schemas.operations import VectorSelectionBBox ExportKind = Literal["dataset", "detection_run", "segmentation_run", "vector_selection"] DetectionExportIntendedUse = Literal["review", "operational"] MapResultMode = Literal["current", "evolution"] class GeoJsonExportRequest(BaseModel): dataset_id: UUID | None = None analysis_run_id: UUID | None = None area_id: UUID | None = None export_kind: ExportKind = "dataset" name: str | None = None bbox: VectorSelectionBBox | None = None limit: int = 250 intended_use: DetectionExportIntendedUse = "review" @model_validator(mode="after") def validate_target(self) -> "GeoJsonExportRequest": if self.export_kind == "dataset" and self.dataset_id is None: raise ValueError("dataset_id is required for dataset GeoJSON exports") if self.export_kind == "vector_selection": if self.dataset_id is None: raise ValueError("dataset_id is required for vector selection GeoJSON exports") if self.bbox is None: raise ValueError("bbox is required for vector selection GeoJSON exports") if self.export_kind in {"detection_run", "segmentation_run"} and self.analysis_run_id is None: raise ValueError("analysis_run_id is required for run GeoJSON exports") if self.intended_use == "operational" and self.export_kind != "detection_run": raise ValueError("operational intended_use is supported only for detection run exports") return self class MetadataExportRequest(BaseModel): project_id: UUID name: str | None = None class ReportExportRequest(BaseModel): project_id: UUID name: str | None = None class MapResultExportRequest(BaseModel): project_id: UUID mode: MapResultMode bbox: VectorSelectionBBox dataset_id: UUID | None = None earlier_dataset_id: UUID | None = None later_dataset_id: UUID | None = None area_id: UUID | None = None partitioned: bool = False product_key: str | None = None partition_scope_key: str | None = None theme_id: str | None = None name: str | None = None @model_validator(mode="after") def validate_map_target(self) -> "MapResultExportRequest": if self.mode == "current" and self.dataset_id is None: raise ValueError("dataset_id is required for current map-result exports") if self.mode == "evolution" and ( self.earlier_dataset_id is None or self.later_dataset_id is None ): raise ValueError("earlier_dataset_id and later_dataset_id are required for evolution exports") if self.partitioned and not self.product_key and not self.partition_scope_key: raise ValueError("product_key or partition_scope_key is required for partitioned exports") return self class ExportRead(BaseModel): id: UUID project_id: UUID analysis_run_id: UUID | None = None export_type: str storage_path: str metadata_json: dict | None = None created_at: datetime | None = None status: str = "ready" model_config = {"from_attributes": True} class ExportCreateResponse(BaseModel): export_id: UUID path: str status: str export_type: str metadata_json: dict | None = None class ExportListResponse(BaseModel): items: list[ExportRead] total: int limit: int offset: int class ExportContentResponse(BaseModel): export_id: UUID export_type: str content: dict