import asyncio
import io
import os
from typing import List

from fastapi import FastAPI, File, HTTPException, UploadFile
from PIL import Image, UnidentifiedImageError

app = FastAPI(title="AI Plant Detection Service")

_model = None
MODEL_CACHE_DIR = os.environ.get("MODEL_CACHE_DIR", "/models")
MAX_FILE_SIZE = 10 * 1024 * 1024  # 10 MB


def get_model():
    global _model
    if _model is None:
        from ultralytics import YOLO
        os.makedirs(MODEL_CACHE_DIR, exist_ok=True)
        try:
            _model = YOLO("foduucom/plant-leaf-detection-and-classification")
        except Exception as e:
            raise RuntimeError(f"Impossible de charger le modèle YOLO: {e}") from e
    return _model


def _run_inference(img: Image.Image) -> list:
    model = get_model()
    results = model.predict(img, conf=0.25, iou=0.45, verbose=False)
    detections = []
    if results and results[0].boxes:
        boxes = results[0].boxes
        names = model.names
        for i in range(min(3, len(boxes))):
            cls_id = int(boxes.cls[i].item())
            conf = float(boxes.conf[i].item())
            detections.append({
                "class_name": names[cls_id],
                "confidence": round(conf, 3),
            })
    return detections


@app.get("/health")
def health():
    return {"status": "ok", "model_loaded": _model is not None}


@app.post("/detect")
async def detect(file: UploadFile = File(...)):
    data = await file.read()

    if len(data) > MAX_FILE_SIZE:
        raise HTTPException(status_code=413, detail="Fichier trop volumineux (max 10 MB)")

    try:
        img = Image.open(io.BytesIO(data)).convert("RGB")
    except (UnidentifiedImageError, OSError) as e:
        raise HTTPException(status_code=400, detail=f"Image invalide: {e}")

    try:
        loop = asyncio.get_event_loop()
        detections = await loop.run_in_executor(None, _run_inference, img)
    except RuntimeError as e:
        raise HTTPException(status_code=503, detail=str(e))

    return detections
