"""Gallery media endpoints.

- ``GET  /api/yatra/media``            public — the site gallery reads this.
- ``POST /api/yatra/media``            admin/superadmin — upload an image.
- ``DELETE /api/yatra/media/{id}``     admin/superadmin — remove an image.

Uploads go server-side to Cloudinary (the API secret never reaches the browser);
the returned metadata is persisted so the gallery can be rebuilt without calling
Cloudinary's Admin API.
"""

from typing import Annotated, Optional

from fastapi import (
    APIRouter,
    Depends,
    File,
    Form,
    HTTPException,
    Query,
    UploadFile,
    status,
)
from sqlalchemy.orm import Session

from .. import cloudinary_service, crud, schemas, security
from ..config import get_settings
from ..database import get_db

router = APIRouter(prefix="/api/yatra/media", tags=["media"])

# Only admins/superadmins may add or remove gallery images.
Manager = Annotated[
    object, Depends(security.require_roles(*security.MANAGE_ROLES))
]

_ALLOWED_TYPES = {"image/jpeg", "image/png", "image/webp", "image/gif", "image/avif"}


@router.get("", response_model=list[schemas.MediaAssetOut])
def list_media(
    db: Annotated[Session, Depends(get_db)],
    category: Optional[str] = Query(None),
    skip: int = Query(0, ge=0),
    limit: int = Query(200, ge=1, le=500),
) -> list[schemas.MediaAssetOut]:
    return crud.list_media_assets(db, category=category, skip=skip, limit=limit)


@router.post("", response_model=schemas.MediaAssetOut, status_code=status.HTTP_201_CREATED)
async def upload_media(
    _: Manager,
    db: Annotated[Session, Depends(get_db)],
    file: Annotated[UploadFile, File(...)],
    title: Annotated[Optional[str], Form()] = None,
    category: Annotated[str, Form()] = "gallery",
) -> schemas.MediaAssetOut:
    settings = get_settings()

    if file.content_type not in _ALLOWED_TYPES:
        raise HTTPException(
            status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE,
            detail=f"Unsupported image type: {file.content_type or 'unknown'}",
        )

    data = await file.read()
    if not data:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST, detail="Empty file."
        )
    if len(data) > settings.max_upload_bytes:
        raise HTTPException(
            status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE,
            detail=f"Image exceeds the {settings.max_upload_bytes // (1024 * 1024)} MB limit.",
        )

    try:
        result = cloudinary_service.upload_image(data)
    except cloudinary_service.CloudinaryNotConfigured as exc:
        raise HTTPException(
            status_code=status.HTTP_503_SERVICE_UNAVAILABLE, detail=str(exc)
        )
    except Exception as exc:  # noqa: BLE001 - surface a clean error to the client
        raise HTTPException(
            status_code=status.HTTP_502_BAD_GATEWAY,
            detail=f"Cloudinary upload failed: {exc}",
        )

    asset = crud.create_media_asset(
        db,
        public_id=result["public_id"],
        secure_url=result["secure_url"],
        title=(title or "").strip() or None,
        category=category.strip() or "gallery",
        format=result.get("format"),
        width=result.get("width"),
        height=result.get("height"),
        bytes=result.get("bytes"),
    )
    return asset


@router.delete("/{asset_id}", status_code=status.HTTP_204_NO_CONTENT)
def delete_media(
    asset_id: int,
    _: Manager,
    db: Annotated[Session, Depends(get_db)],
) -> None:
    asset = crud.get_media_asset(db, asset_id)
    if asset is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND, detail="Media asset not found"
        )
    # Best-effort Cloudinary delete; the DB row is removed regardless so the
    # gallery never shows a dangling entry.
    try:
        cloudinary_service.destroy_image(asset.public_id)
    except cloudinary_service.CloudinaryNotConfigured:
        pass
    crud.delete_media_asset(db, asset)
