#!/usr/bin/env python3
from __future__ import annotations

import argparse
import json
from pathlib import Path


TOKEN_FR = {
    "healthy": "saine",
    "leaf": "feuille",
    "plant": "plante",
    "disease": "maladie",
    "blight": "mildiou",
    "rust": "rouille",
    "spot": "tache",
    "scab": "tavelure",
    "mold": "moisissure",
    "mildew": "oidium",
    "powdery": "poudreux",
    "bacterial": "bacterien",
    "viral": "viral",
    "virus": "virus",
    "yellow": "jaune",
    "mosaic": "mosaique",
    "late": "tardif",
    "early": "precoce",
    "septoria": "septoriose",
    "target": "cible",
    "black": "noire",
    "rot": "pourriture",
}


def translate_label_to_fr(label: str) -> str:
    tokens = (
        label.replace("-", " ")
        .replace("_", " ")
        .replace(",", " ")
        .replace("(", " ")
        .replace(")", " ")
        .split()
    )
    if not tokens:
        return label
    translated = [TOKEN_FR.get(tok.lower(), tok.lower()) for tok in tokens]
    return " ".join(translated)


def resolve_model(model_arg: str) -> tuple[str, str]:
    model_path = Path(model_arg)
    if model_path.exists():
        return str(model_path), model_arg

    lower = model_arg.lower()
    if "/" in model_arg and not lower.endswith((".pt", ".onnx", ".engine", ".torchscript")):
        try:
            from huggingface_hub import hf_hub_download
        except Exception as exc:
            raise SystemExit(
                "Le modèle semble être un repo Hugging Face. Installe:\n"
                "pip install huggingface_hub\n"
                f"Détail: {exc}"
            )

        try:
            downloaded = hf_hub_download(repo_id=model_arg, filename="best.pt")
            return downloaded, model_arg
        except Exception as exc:
            raise SystemExit(
                f"Impossible de télécharger best.pt depuis le repo Hugging Face '{model_arg}'.\n"
                f"Détail: {exc}"
            )

    return model_arg, model_arg


def main() -> int:
    parser = argparse.ArgumentParser(
        description="Test YOLO feuille/plante avec sortie JSON et image annotée."
    )
    parser.add_argument("--image", required=True, help="Chemin image à analyser")
    parser.add_argument(
        "--model",
        default="foduucom/plant-leaf-detection-and-classification",
        help="Chemin vers .pt/.onnx ou repo Hugging Face (best.pt)",
    )
    parser.add_argument("--conf", type=float, default=0.25, help="Seuil confiance")
    parser.add_argument("--iou", type=float, default=0.45, help="Seuil IoU NMS")
    parser.add_argument("--max-det", type=int, default=1000, help="Nombre max de détections")
    parser.add_argument(
        "--json-out",
        default="test_yolo/output/detections.json",
        help="Fichier JSON de sortie",
    )
    parser.add_argument(
        "--image-out",
        default="test_yolo/output/annotated.jpg",
        help="Image annotée de sortie",
    )
    args = parser.parse_args()

    image_path = Path(args.image)
    if not image_path.exists():
        raise SystemExit(f"Image introuvable: {image_path}")

    try:
        import cv2
        from ultralytics import YOLO
    except Exception as exc:
        raise SystemExit(
            "Dépendances manquantes. Installe dans un venv:\n"
            "pip install ultralytics opencv-python matplotlib huggingface_hub\n"
            f"Détail: {exc}"
        )

    model_source, model_display = resolve_model(args.model)
    model = YOLO(model_source)
    model.overrides["conf"] = args.conf
    model.overrides["iou"] = args.iou
    model.overrides["max_det"] = args.max_det

    results = model.predict(str(image_path))
    result = results[0]

    boxes = result.boxes
    names = getattr(result, "names", {})
    detections: list[dict] = []
    for i, box in enumerate(boxes):
        cls_id = int(box.cls.item())
        conf = float(box.conf.item())
        xyxy = [float(v) for v in box.xyxy[0].tolist()]
        detections.append(
            {
                "index": i,
                "class_id": cls_id,
                "class_name": names.get(cls_id, str(cls_id)),
                "class_name_fr": translate_label_to_fr(names.get(cls_id, str(cls_id))),
                "confidence": conf,
                "bbox_xyxy": xyxy,
            }
        )

    payload = {
        "image": str(image_path),
        "model": model_display,
        "model_source": model_source,
        "params": {"conf": args.conf, "iou": args.iou, "max_det": args.max_det},
        "count": len(detections),
        "detections": detections,
    }

    json_out = Path(args.json_out)
    json_out.parent.mkdir(parents=True, exist_ok=True)
    json_out.write_text(json.dumps(payload, ensure_ascii=False, indent=2), encoding="utf-8")

    annotated = result.plot()
    image_out = Path(args.image_out)
    image_out.parent.mkdir(parents=True, exist_ok=True)
    cv2.imwrite(str(image_out), annotated)

    print(f"Détections: {len(detections)}")
    print(f"JSON: {json_out}")
    print(f"Image annotée: {image_out}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
