from datetime import date

from fastapi import APIRouter, Depends, Form, HTTPException, Request, UploadFile
from fastapi.responses import RedirectResponse
from fastapi.templating import Jinja2Templates
from sqlalchemy.orm import Session

from app import models
from app.database import get_db
from app.securite import verifier_jeton_csrf
from app.uploads import enregistrer_fichier, supprimer_fichier
from app.utils import vers_float, vers_int

router = APIRouter(prefix="/terrains", tags=["terrains"])
templates = Jinja2Templates(directory="app/templates")


@router.get("")
def accueil_terrains(request: Request, db: Session = Depends(get_db)):
    fermes = db.query(models.Ferme).order_by(models.Ferme.nom).all()
    parcelles_sans_ferme = (
        db.query(models.Parcelle).filter(models.Parcelle.ferme_id.is_(None)).order_by(models.Parcelle.nom).all()
    )
    return templates.TemplateResponse(
        "terrains/liste.html",
        {"request": request, "fermes": fermes, "parcelles_sans_ferme": parcelles_sans_ferme},
    )


# ---------------------------------------------------------------------------
# Fermes
# ---------------------------------------------------------------------------
@router.get("/fermes/nouveau")
def formulaire_ferme(request: Request):
    return templates.TemplateResponse("terrains/ferme_formulaire.html", {"request": request, "ferme": None})


@router.post("/fermes/nouveau", dependencies=[Depends(verifier_jeton_csrf)])
async def creer_ferme(
    request: Request,
    nom: str = Form(...),
    localisation: str | None = Form(None),
    notes: str | None = Form(None),
    photo_satellite: UploadFile | None = None,
    db: Session = Depends(get_db),
):
    photo_path = None
    if photo_satellite is not None and photo_satellite.filename:
        try:
            photo_path = await enregistrer_fichier(photo_satellite, "satellites")
        except ValueError as exc:
            return templates.TemplateResponse(
                "terrains/ferme_formulaire.html",
                {"request": request, "ferme": None, "erreur": str(exc)},
                status_code=400,
            )

    ferme = models.Ferme(nom=nom, localisation=localisation, notes=notes, photo_satellite_path=photo_path)
    db.add(ferme)
    db.commit()
    return RedirectResponse(url=f"/terrains/fermes/{ferme.id}?succes=Ferme créée", status_code=303)


@router.get("/fermes/{ferme_id}")
def detail_ferme(ferme_id: int, request: Request, db: Session = Depends(get_db)):
    ferme = db.get(models.Ferme, ferme_id)
    if ferme is None:
        raise HTTPException(status_code=404, detail="Ferme introuvable")
    return templates.TemplateResponse("terrains/ferme_detail.html", {"request": request, "ferme": ferme})


@router.get("/fermes/{ferme_id}/modifier")
def formulaire_modif_ferme(ferme_id: int, request: Request, db: Session = Depends(get_db)):
    ferme = db.get(models.Ferme, ferme_id)
    if ferme is None:
        raise HTTPException(status_code=404, detail="Ferme introuvable")
    return templates.TemplateResponse("terrains/ferme_formulaire.html", {"request": request, "ferme": ferme})


@router.post("/fermes/{ferme_id}/modifier", dependencies=[Depends(verifier_jeton_csrf)])
async def modifier_ferme(
    ferme_id: int,
    request: Request,
    nom: str = Form(...),
    localisation: str | None = Form(None),
    notes: str | None = Form(None),
    photo_satellite: UploadFile | None = None,
    db: Session = Depends(get_db),
):
    ferme = db.get(models.Ferme, ferme_id)
    if ferme is None:
        raise HTTPException(status_code=404, detail="Ferme introuvable")

    if photo_satellite is not None and photo_satellite.filename:
        try:
            nouvelle_photo = await enregistrer_fichier(photo_satellite, "satellites")
        except ValueError as exc:
            return templates.TemplateResponse(
                "terrains/ferme_formulaire.html",
                {"request": request, "ferme": ferme, "erreur": str(exc)},
                status_code=400,
            )
        supprimer_fichier(ferme.photo_satellite_path)
        ferme.photo_satellite_path = nouvelle_photo

    ferme.nom = nom
    ferme.localisation = localisation
    ferme.notes = notes
    db.commit()
    return RedirectResponse(url=f"/terrains/fermes/{ferme_id}?succes=Ferme mise à jour", status_code=303)


@router.post("/fermes/{ferme_id}/supprimer", dependencies=[Depends(verifier_jeton_csrf)])
def supprimer_ferme(ferme_id: int, db: Session = Depends(get_db)):
    ferme = db.get(models.Ferme, ferme_id)
    if ferme is None:
        raise HTTPException(status_code=404, detail="Ferme introuvable")
    supprimer_fichier(ferme.photo_satellite_path)
    for parcelle in ferme.parcelles:
        parcelle.ferme_id = None
    db.delete(ferme)
    db.commit()
    return RedirectResponse(
        url="/terrains?succes=Ferme supprimée (les parcelles associées sont conservées)", status_code=303
    )


# ---------------------------------------------------------------------------
# Parcelles
# ---------------------------------------------------------------------------
@router.get("/nouveau")
def formulaire_creation(request: Request, ferme_id: int | None = None, db: Session = Depends(get_db)):
    fermes = db.query(models.Ferme).order_by(models.Ferme.nom).all()
    return templates.TemplateResponse(
        "terrains/formulaire.html",
        {"request": request, "parcelle": None, "fermes": fermes, "ferme_id_preselection": ferme_id},
    )


@router.post("/nouveau", dependencies=[Depends(verifier_jeton_csrf)])
async def creer_parcelle(
    request: Request,
    nom: str = Form(...),
    ferme_id: str | None = Form(None),
    superficie_m2: str | None = Form(None),
    localisation: str | None = Form(None),
    culture_actuelle: str | None = Form(None),
    notes: str | None = Form(None),
    plan: UploadFile | None = None,
    db: Session = Depends(get_db),
):
    erreur = None
    plan_path = None
    if plan is not None and plan.filename:
        try:
            plan_path = await enregistrer_fichier(plan, "plans")
        except ValueError as exc:
            erreur = str(exc)

    if erreur:
        fermes = db.query(models.Ferme).order_by(models.Ferme.nom).all()
        return templates.TemplateResponse(
            "terrains/formulaire.html",
            {"request": request, "parcelle": None, "fermes": fermes, "erreur": erreur},
            status_code=400,
        )

    ferme_id_int = vers_int(ferme_id)
    parcelle = models.Parcelle(
        nom=nom,
        ferme_id=ferme_id_int,
        superficie_m2=vers_float(superficie_m2),
        localisation=localisation,
        culture_actuelle=culture_actuelle,
        notes=notes,
        plan_path=plan_path,
    )
    db.add(parcelle)
    db.commit()
    destination = f"/terrains/fermes/{ferme_id_int}" if ferme_id_int else "/terrains"
    return RedirectResponse(url=f"{destination}?succes=Parcelle créée", status_code=303)


@router.get("/{parcelle_id}")
def detail_parcelle(parcelle_id: int, request: Request, db: Session = Depends(get_db)):
    parcelle = db.get(models.Parcelle, parcelle_id)
    if parcelle is None:
        raise HTTPException(status_code=404, detail="Parcelle introuvable")
    return templates.TemplateResponse(
        "terrains/detail.html", {"request": request, "parcelle": parcelle}
    )


@router.get("/{parcelle_id}/modifier")
def formulaire_modification(parcelle_id: int, request: Request, db: Session = Depends(get_db)):
    parcelle = db.get(models.Parcelle, parcelle_id)
    if parcelle is None:
        raise HTTPException(status_code=404, detail="Parcelle introuvable")
    fermes = db.query(models.Ferme).order_by(models.Ferme.nom).all()
    return templates.TemplateResponse(
        "terrains/formulaire.html", {"request": request, "parcelle": parcelle, "fermes": fermes}
    )


@router.post("/{parcelle_id}/modifier", dependencies=[Depends(verifier_jeton_csrf)])
async def modifier_parcelle(
    parcelle_id: int,
    request: Request,
    nom: str = Form(...),
    ferme_id: str | None = Form(None),
    superficie_m2: str | None = Form(None),
    localisation: str | None = Form(None),
    culture_actuelle: str | None = Form(None),
    notes: str | None = Form(None),
    plan: UploadFile | None = None,
    db: Session = Depends(get_db),
):
    parcelle = db.get(models.Parcelle, parcelle_id)
    if parcelle is None:
        raise HTTPException(status_code=404, detail="Parcelle introuvable")

    if plan is not None and plan.filename:
        try:
            nouveau_plan = await enregistrer_fichier(plan, "plans")
        except ValueError as exc:
            fermes = db.query(models.Ferme).order_by(models.Ferme.nom).all()
            return templates.TemplateResponse(
                "terrains/formulaire.html",
                {"request": request, "parcelle": parcelle, "fermes": fermes, "erreur": str(exc)},
                status_code=400,
            )
        supprimer_fichier(parcelle.plan_path)
        parcelle.plan_path = nouveau_plan

    parcelle.nom = nom
    parcelle.ferme_id = vers_int(ferme_id)
    parcelle.superficie_m2 = vers_float(superficie_m2)
    parcelle.localisation = localisation
    parcelle.culture_actuelle = culture_actuelle
    parcelle.notes = notes
    db.commit()
    return RedirectResponse(url=f"/terrains/{parcelle_id}?succes=Parcelle mise à jour", status_code=303)


@router.post("/{parcelle_id}/supprimer", dependencies=[Depends(verifier_jeton_csrf)])
def supprimer_parcelle(parcelle_id: int, db: Session = Depends(get_db)):
    parcelle = db.get(models.Parcelle, parcelle_id)
    if parcelle is None:
        raise HTTPException(status_code=404, detail="Parcelle introuvable")
    ferme_id = parcelle.ferme_id
    supprimer_fichier(parcelle.plan_path)
    for photo in parcelle.photos:
        supprimer_fichier(photo.chemin)
    db.delete(parcelle)
    db.commit()
    destination = f"/terrains/fermes/{ferme_id}" if ferme_id else "/terrains"
    return RedirectResponse(url=f"{destination}?succes=Parcelle supprimée", status_code=303)


@router.post("/{parcelle_id}/photos", dependencies=[Depends(verifier_jeton_csrf)])
async def ajouter_photo(
    parcelle_id: int,
    photo: UploadFile,
    db: Session = Depends(get_db),
):
    parcelle = db.get(models.Parcelle, parcelle_id)
    if parcelle is None:
        raise HTTPException(status_code=404, detail="Parcelle introuvable")

    try:
        chemin = await enregistrer_fichier(photo, "photos")
    except ValueError as exc:
        return RedirectResponse(
            url=f"/terrains/{parcelle_id}?erreur={exc}", status_code=303
        )

    db.add(models.ParcellePhoto(parcelle_id=parcelle_id, chemin=chemin))
    db.commit()
    return RedirectResponse(url=f"/terrains/{parcelle_id}?succes=Photo ajoutée", status_code=303)


@router.post("/photos/{photo_id}/supprimer", dependencies=[Depends(verifier_jeton_csrf)])
def supprimer_photo(photo_id: int, db: Session = Depends(get_db)):
    photo = db.get(models.ParcellePhoto, photo_id)
    if photo is None:
        raise HTTPException(status_code=404, detail="Photo introuvable")
    parcelle_id = photo.parcelle_id
    supprimer_fichier(photo.chemin)
    db.delete(photo)
    db.commit()
    return RedirectResponse(url=f"/terrains/{parcelle_id}?succes=Photo supprimée", status_code=303)


# ---------------------------------------------------------------------------
# Plantations (date, variété, nombre de plants) par parcelle
# ---------------------------------------------------------------------------
@router.post("/{parcelle_id}/plantations", dependencies=[Depends(verifier_jeton_csrf)])
def ajouter_plantation(
    parcelle_id: int,
    date_plantation: date = Form(...),
    variete: str = Form(...),
    nombre_plants: str | None = Form(None),
    notes: str | None = Form(None),
    db: Session = Depends(get_db),
):
    parcelle = db.get(models.Parcelle, parcelle_id)
    if parcelle is None:
        raise HTTPException(status_code=404, detail="Parcelle introuvable")

    db.add(
        models.Plantation(
            parcelle_id=parcelle_id,
            date_plantation=date_plantation,
            variete=variete,
            nombre_plants=vers_int(nombre_plants),
            notes=notes,
        )
    )
    db.commit()
    return RedirectResponse(url=f"/terrains/{parcelle_id}?succes=Plantation ajoutée", status_code=303)


@router.post("/plantations/{plantation_id}/supprimer", dependencies=[Depends(verifier_jeton_csrf)])
def supprimer_plantation(plantation_id: int, db: Session = Depends(get_db)):
    plantation = db.get(models.Plantation, plantation_id)
    if plantation is None:
        raise HTTPException(status_code=404, detail="Plantation introuvable")
    parcelle_id = plantation.parcelle_id
    db.delete(plantation)
    db.commit()
    return RedirectResponse(url=f"/terrains/{parcelle_id}?succes=Plantation supprimée", status_code=303)
