"""
AOI (Area of Interest) API Endpoints
Handles polygon selection, validation, and Unity bundle generation
"""
from fastapi import APIRouter, HTTPException, Path, Query, BackgroundTasks
from fastapi.responses import JSONResponse, FileResponse
from pydantic import BaseModel, Field
from typing import Optional
from datetime import datetime
import uuid
import structlog

from config import settings
from models.aoi import AOIRequest, AOIResponse, AOIStatus, AOIManifest
from services.aoi_packager import AOIPackagerService
from services.osm_extractor import OSMExtractorService

logger = structlog.get_logger(__name__)
router = APIRouter()

# Initialize services
aoi_packager = AOIPackagerService()
osm_extractor = OSMExtractorService()


@router.post("", response_model=AOIResponse)
async def create_aoi(
    request: AOIRequest,
    background_tasks: BackgroundTasks,
):
    """
    Create a new AOI (Area of Interest) for Unity 3D export.

    Validates the polygon, checks size limits (max 4 km²), and queues
    bundle generation. Returns immediately with a status URL.

    The bundle will contain:
    - Terrain heightmap
    - OSM features (buildings, roads, water, etc.)
    - Learning node positions
    - Attribution information
    """
    # Validate polygon
    try:
        area_km2 = aoi_packager.calculate_area_km2(request.polygon)
    except ValueError as e:
        raise HTTPException(status_code=400, detail=f"Invalid polygon: {str(e)}")

    # Check size limit
    if area_km2 > settings.max_aoi_size_km2:
        raise HTTPException(
            status_code=400,
            detail=f"AOI too large: {area_km2:.2f} km² exceeds maximum of {settings.max_aoi_size_km2} km²",
        )

    # Check if polygon is within Germany bounds
    if not aoi_packager.is_within_germany(request.polygon):
        raise HTTPException(
            status_code=400,
            detail="AOI must be within Germany. Bounds: [5.87°E, 47.27°N] to [15.04°E, 55.06°N]",
        )

    # Generate AOI ID
    aoi_id = str(uuid.uuid4())

    # Create AOI record
    aoi_data = {
        "id": aoi_id,
        "polygon": request.polygon,
        "theme": request.theme,
        "quality": request.quality,
        "area_km2": area_km2,
        "status": AOIStatus.QUEUED,
        "created_at": datetime.utcnow().isoformat(),
    }

    # Start background processing
    background_tasks.add_task(
        aoi_packager.process_aoi,
        aoi_id=aoi_id,
        polygon=request.polygon,
        theme=request.theme,
        quality=request.quality,
    )

    logger.info(
        "AOI created",
        aoi_id=aoi_id,
        area_km2=area_km2,
        theme=request.theme,
    )

    return AOIResponse(
        aoi_id=aoi_id,
        status=AOIStatus.QUEUED,
        area_km2=area_km2,
        estimated_size_mb=aoi_packager.estimate_bundle_size_mb(area_km2, request.quality),
        message="AOI queued for processing",
    )


@router.get("/{aoi_id}", response_model=AOIResponse)
async def get_aoi_status(
    aoi_id: str = Path(..., description="AOI UUID"),
):
    """
    Get the status of an AOI processing job.

    Returns current status (queued, processing, completed, failed)
    and download URLs when ready.
    """
    aoi_data = await aoi_packager.get_aoi_status(aoi_id)

    if aoi_data is None:
        raise HTTPException(status_code=404, detail="AOI not found")

    response = AOIResponse(
        aoi_id=aoi_id,
        status=aoi_data["status"],
        area_km2=aoi_data.get("area_km2", 0),
        estimated_size_mb=aoi_data.get("estimated_size_mb", 0),
        message=aoi_data.get("message", ""),
    )

    # Add download URLs if completed
    if aoi_data["status"] == AOIStatus.COMPLETED:
        response.download_url = f"/api/v1/aoi/{aoi_id}/bundle.zip"
        response.manifest_url = f"/api/v1/aoi/{aoi_id}/manifest.json"
        response.completed_at = aoi_data.get("completed_at")

    return response


@router.get("/{aoi_id}/manifest.json")
async def get_aoi_manifest(
    aoi_id: str = Path(..., description="AOI UUID"),
):
    """
    Get the Unity bundle manifest for an AOI.

    The manifest contains:
    - Terrain configuration
    - Asset list and paths
    - Learning node positions
    - Attribution requirements
    """
    manifest = await aoi_packager.get_manifest(aoi_id)

    if manifest is None:
        raise HTTPException(status_code=404, detail="Manifest not found or AOI not ready")

    return JSONResponse(content=manifest)


@router.get("/{aoi_id}/bundle.zip")
async def download_aoi_bundle(
    aoi_id: str = Path(..., description="AOI UUID"),
):
    """
    Download the complete AOI bundle as a ZIP file.

    Contains all assets needed for Unity 3D rendering:
    - terrain.heightmap (16-bit PNG)
    - osm_features.json (buildings, roads, etc.)
    - learning_nodes.json (educational content positions)
    - attribution.json (required license notices)
    """
    bundle_path = await aoi_packager.get_bundle_path(aoi_id)

    if bundle_path is None:
        raise HTTPException(status_code=404, detail="Bundle not found or AOI not ready")

    return FileResponse(
        path=bundle_path,
        filename=f"geo-lernwelt-{aoi_id[:8]}.zip",
        media_type="application/zip",
    )


@router.delete("/{aoi_id}")
async def delete_aoi(
    aoi_id: str = Path(..., description="AOI UUID"),
):
    """
    Delete an AOI and its bundle.

    Implements DSGVO data minimization - users can delete their data.
    """
    success = await aoi_packager.delete_aoi(aoi_id)

    if not success:
        raise HTTPException(status_code=404, detail="AOI not found")

    logger.info("AOI deleted", aoi_id=aoi_id)

    return {"message": "AOI deleted successfully", "aoi_id": aoi_id}


@router.get("/{aoi_id}/preview")
async def get_aoi_preview(
    aoi_id: str = Path(..., description="AOI UUID"),
    width: int = Query(512, ge=64, le=2048, description="Preview width"),
    height: int = Query(512, ge=64, le=2048, description="Preview height"),
):
    """
    Get a preview image of the AOI.

    Returns a rendered preview showing terrain, OSM features,
    and learning node positions.
    """
    preview_data = await aoi_packager.generate_preview(aoi_id, width, height)

    if preview_data is None:
        raise HTTPException(status_code=404, detail="Preview not available")

    from fastapi.responses import Response

    return Response(
        content=preview_data,
        media_type="image/png",
    )


@router.post("/validate")
async def validate_aoi_polygon(
    polygon: dict,
):
    """
    Validate an AOI polygon without creating it.

    Checks:
    - Valid GeoJSON format
    - Within Germany bounds
    - Within size limits
    - Not self-intersecting
    """
    try:
        # Validate geometry
        is_valid, message = aoi_packager.validate_polygon(polygon)

        if not is_valid:
            return {
                "valid": False,
                "error": message,
            }

        # Calculate area
        area_km2 = aoi_packager.calculate_area_km2(polygon)

        # Check bounds
        within_germany = aoi_packager.is_within_germany(polygon)

        # Check size
        within_size_limit = area_km2 <= settings.max_aoi_size_km2

        return {
            "valid": is_valid and within_germany and within_size_limit,
            "area_km2": round(area_km2, 3),
            "within_germany": within_germany,
            "within_size_limit": within_size_limit,
            "max_size_km2": settings.max_aoi_size_km2,
            "estimated_bundle_size_mb": aoi_packager.estimate_bundle_size_mb(area_km2, "medium"),
        }

    except Exception as e:
        return {
            "valid": False,
            "error": str(e),
        }


@router.get("/templates/mainau")
async def get_mainau_template():
    """
    Get pre-configured AOI template for Mainau island (demo location).

    Mainau is a small island in Lake Constance (Bodensee) -
    perfect for educational geography lessons.
    """
    return {
        "name": "Insel Mainau",
        "description": "Blumeninsel im Bodensee - ideal fuer Erdkunde-Unterricht",
        "polygon": {
            "type": "Polygon",
            "coordinates": [
                [
                    [9.1875, 47.7055],
                    [9.1975, 47.7055],
                    [9.1975, 47.7115],
                    [9.1875, 47.7115],
                    [9.1875, 47.7055],
                ]
            ],
        },
        "center": [9.1925, 47.7085],
        "area_km2": 0.45,
        "suggested_themes": ["topographie", "vegetation", "landnutzung"],
        "features": [
            "Schloss und Schlosskirche",
            "Botanischer Garten",
            "Bodensee-Ufer",
            "Waldgebiete",
        ],
    }
