"""VTON (Virtual Try-On) router: composite garments onto a person image."""

import uuid

from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile
from sqlalchemy.ext.asyncio import AsyncSession

from app.dependencies import get_db, get_vton_service
from app.schemas.common import ImageModel
from app.schemas.vton import VtonGenerateResponse
from app.services.vton_service import VtonService
from app.utils.image import fetch_image_bytes

router = APIRouter(prefix="/api/v1/vton", tags=["vton"])


@router.post("/generate", response_model=VtonGenerateResponse)
async def generate_vton(
    image: UploadFile | None = File(None),
    image_url: str | None = Form(None),
    garment_ids: list[uuid.UUID] = Form(...),
    user_id: uuid.UUID | None = Form(None),
    image_model: ImageModel | None = Form(None),
    db: AsyncSession = Depends(get_db),
    vton_svc: VtonService = Depends(get_vton_service),
):
    """Generate a virtual try-on image.

    Composites the selected garments (from the wardrobe) onto the person in
    the uploaded image. Requires a detectable face. Each selected garment
    must already have a ghost-mannequin image generated.

    Accepts the person image via either ``image`` (multipart file upload) or
    ``image_url`` (HTTP/HTTPS URL — downloaded server-side to avoid browser
    CORS restrictions). Exactly one of the two must be provided.

    ``image_model`` selects the OpenAI image-generation model
    (``gpt-image-2`` / ``gpt-image-1.5``); when omitted the server default is
    used. Ignored by the Gemini provider.

    If the person photo is an upper-body crop, the LLM will silently skip
    bottom-category garments; the response reports skipped IDs separately.
    """
    has_file = bool(image is not None and image.filename)
    has_url = bool(image_url and image_url.strip())
    if has_file == has_url:
        raise HTTPException(
            status_code=400,
            detail="image 파일 또는 image_url 중 정확히 하나를 제공해야 합니다.",
        )

    try:
        if has_file:
            image_bytes = await image.read()
        else:
            image_bytes = await fetch_image_bytes(image_url.strip())
    except ValueError as e:
        raise HTTPException(status_code=400, detail=str(e))

    try:
        result = await vton_svc.generate(
            db,
            image_bytes,
            garment_ids,
            user_id,
            image_model.value if image_model else None,
        )
    except LookupError as e:
        raise HTTPException(status_code=404, detail=str(e))
    except ValueError as e:
        # Face missing, empty list, ghost missing, decode failure
        raise HTTPException(status_code=400, detail=str(e))
    except RuntimeError as e:
        # LLM returned nothing / external failure
        raise HTTPException(status_code=502, detail=str(e))
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"VTON 생성 실패: {e}")

    return VtonGenerateResponse(
        result_image_url=f"/storage/{result.path}",
        result_image_path=result.path,
        used_garment_ids=result.used_ids,
        skipped_garment_ids=result.skipped_ids,
        llm_note=result.note,
    )
