"""Views pour la gestion des produits."""

from django.shortcuts import render, redirect
from django.core.paginator import Paginator
from django.db.models import Sum

# from django.views.decorators.csrf import csrf_exempt
from django.contrib.auth.decorators import login_required

from django.http import JsonResponse

from .models import (
    Categorie,
    Produit,
    Demander,
    Fournisseur,
    Commander
)

from .forms import (
    EnregistrementProduit,
    EnregistrementCategorie,
    CommanderProduit,
    DemanderProduit,
)

def gestion_affichage_demande(
        request,
        option_validation_chef,
        ordre_inverse=False
    ):
    """Affichez les demandes de produit selon le profil de l'utilisateur.

    Parameters
    ----------
    request : HttpRequest
        La requête HTTP entrante.
    option_validation_chef : bool or None
        Filtre pour la validation par le chef de département.
        1- True : demandes validées par le chef.
        2- False : demandes non validées par le chef.
        3- None : demandes en attentes.
    ordre_inverse : bool, optional
        Si True, les demandes sont triées par ordre décroissant,
        par défaut False.

    Returns
    -------
    QuerySet:
        Ensemble des demandes filtrées selon les critères spécifiés.

    """
    mes_demandes = Demander.objects.filter(
        valider_par_chef=option_validation_chef, user=request.user.profile
    )
    demandes_departement = None

    if request.user.profile.chef_departement:
        demandes_departement = Demander.objects.filter(
            valider_par_chef=option_validation_chef,
            user__departement=request.user.profile.departement,
        )

    if ordre_inverse:
        return (
            (mes_demandes | demandes_departement).order_by("-id")
            if demandes_departement
            else mes_demandes
        )
    return (
        (mes_demandes | demandes_departement)
        if demandes_departement
        else mes_demandes
    )


@login_required(login_url="login")
def index(request):
    """Gérer le rendu de la page d'accueil de la gestion des produits.

    Parameters
    ----------
    request : HttpRequest
        La requête HTTP entrante.

    Returns
    -------
    HttpResponse
        La réponse HTTP contenant la page rendue.

    """
    liste_produit = Produit.objects.all().order_by("-id")
    liste_categorie = Categorie.objects.all().order_by("categorie")

    liste_produit_finale = [
        calcul_stock_produit(produit) for produit in liste_produit
    ]

    pagination = Paginator(liste_produit_finale, 8)

    page_number = request.GET.get("page")
    page_obj = pagination.get_page(page_number)

    return render(
        request,
        "gestion_produit/index.html",
        {
            "formulaireEnregistrementCategorie": EnregistrementCategorie,
            "formulaireEnregistrementProduit": EnregistrementProduit,
            "formulaireCommanderProduit": CommanderProduit,
            "formulaireDemanderProduit": DemanderProduit,
            "mes_demandes": gestion_affichage_demande(
                request, option_validation_chef=None
            ),
            "page_obj": page_obj,
            "liste_categorie": liste_categorie,
        },
    )


def liste_categories(_request):
    """Recuperez et renvoyez la liste des catégories de produit au format JSON.

    Parameters
    ----------
    request : HttpRequest
        La requête HTTP entrante.

    Returns
    -------
    JsonResponse
        Réponse JSON contenant la liste des catégories de produits.

    """
    mes_categories = [
        {"categorie": categorie.categorie}
        for categorie in Categorie.objects.all()
    ]

    return JsonResponse(mes_categories, safe=False)

@login_required(login_url="login")
def enregistrer_produit(request):
    """Enregistrez un nouveau produit à partir des données POST.

    Parameters
    ----------
    request : HttpRequest
        La requête HTTP entrante.

    Returns
    -------
    JsonResponse
        Réponse JSON indiquant le succès ou l'échec de l'enregistrement.

    """
    if request.method == "POST":
        form = EnregistrementProduit(request.POST, request.FILES)
        if form.is_valid():
            form.save()
            return JsonResponse(
                {"success": True, "message": "Produit enregistré avec succès"}
            )
        return JsonResponse(
            {
                "success": False,
                "message": "L'enregistrement du produit a échoué",
            }
        )

    return redirect("gestion_produit:index")

@login_required(login_url="login")
def detail_produit(request, id_produit):
    """Renvoyez les détails d'un produit spécifique au format JSON.

    Parameters
    ----------
    request : HttpRequest
        La requête HTTP entrante.
    id_produit : int
        L'ID du produit dont on veut récupérer les détails.

    Returns
    -------
    JsonResponse
        Réponse JSON contenant les détails du produit.

    """

    detail_produit = calcul_stock_produit(Produit.objects.get(id=id_produit))

    categories = Categorie.objects.all()

    produit = {
        "detailId": detail_produit["id"],
        "detailLibelle": detail_produit["libelle"],
        "detailCategorie": detail_produit["categorie_id"],
        "detailConditionnement": detail_produit["conditionnement"],
        "detailSeuilPreRupture": detail_produit["seuil_pre_rupture"],
        "detailQuantiteStock": detail_produit["stockActuel"],
        "detailImage": detail_produit["image"].url if detail_produit["image"] else "",
        "listeCategorie": [
            {"id": categorie.id, "categorie": categorie.categorie}
            for categorie in categories
        ],
    }

    return JsonResponse(produit)

@login_required(login_url="login")
def enregistrer_modification_produit(request):
    """Enregistrez les modifications apportées au produit à partir des données POST.

    Parameters
    ----------
    request : HttpRequest
        La requête HTTP entrante.

    Returns
    -------
    JsonResponse
        Réponse JSON indiquant le succès ou l'échec de l'enregistrement.

    """
    if request.method == "POST":
        id_produit = request.POST.get("id_produit")
        produit_instance = Produit.objects.get(id=id_produit)
        produit_instance.libelle = request.POST.get("libelle")
        produit_instance.conditionnement = request.POST.get("conditionnement")
        produit_instance.seuil_pre_rupture = request.POST.get("seuil_pre_rupture")

        categorie_id = request.POST.get("categorie")
        produit_instance.categorie = Categorie.objects.get(id=categorie_id)
        produit_instance.quantite_stock = request.POST.get("quantite_stock")
        produit_instance.save()

        return JsonResponse(
            {"success": True, "message": "Produit modifié avec succès"}
        )

    return redirect("gestion_produit:index")

@login_required(login_url="login")
def enregistrer_commande(request):
    """Enregistrez une nouvelle commande de produit."""
    if request.method == "POST":
        form = CommanderProduit(request.POST)
        if form.is_valid():
            form.save()

    return redirect("gestion_produit:index")

@login_required(login_url="login")
def enregistrer_demande(request):
    """Enregistrez une nouvelle demande de produit."""
    if request.method == "POST":
        form = DemanderProduit(request.POST)
        if form.is_valid():
            ma_demande = form.save(commit=False)
            ma_demande.user = request.user.profile
            if request.user.profile.chef_departement:
                ma_demande.valider_par_chef = True

            ma_demande.save()
    return redirect("gestion_produit:index")

@login_required(login_url="login")
def liste_demandes(request):
    """Retournez la liste des demandes de produits au format JSON."""
    liste_demandes = gestion_affichage_demande(
        request, option_validation_chef=True, ordre_inverse=True
    )
    les_demandes = [
        {
            "dateDemande": demande.date_de_mise_a_dispo_souhaite,
            "produit": demande.produit.libelle,
            "motifs": demande.motifs,
            "a_rendre": demande.a_rendre,
            "dateDeMiseADispoSouhaite": demande.date_de_mise_a_dispo_souhaite,
            "valider_par_chef": demande.valider_par_chef,
            "valider_par_logisticien": demande.valider_par_logisticien,
            "motifs_refus": demande.motif_refus,
        }
        for demande in liste_demandes
    ]

    return JsonResponse(les_demandes, safe=False)

@login_required(login_url="login")
def detail_demande(request, id_demande):
    """Renvoyez les détails d'une demande spécifique de produit."""
    detail_demande = Demander.objects.get(id=id_demande)

    demande = {
        "detailNom": detail_demande.produit.libelle,
        "detailCategorie": detail_demande.produit.categorie.categorie,
        "detailmotif": detail_demande.motifs,
        "detailDeMiseADispo": detail_demande.date_de_mise_a_dispo_souhaite,
        "detailARendre": detail_demande.a_rendre,
        "chef_departement": request.user.profile.chef_departement,
    }

    return JsonResponse(demande)

@login_required(login_url="login")
def update_statut(request):
    """Met à jour le statut d'une demande de produit.

    Parameters
    ----------
    request : HttpRequest
        La requête HTTP entrante.
        request.id : int
            L'ID de la demande à mettre à jour.
        request.action : int
            L'action effectuée
            1: Pour confirmer
            0: Pour refuser
        request.emetteur : str
            L'émetteur de la demande ('chef' ou 'logisticien').
        request.motif_refus : str
            Le motif de refus.

    Returns
    -------
    JsonResponse
        Réponse JSON indiquant le succès ou l'échec de la mise à jour.

    """
    if request.method == "POST":
        produit_id = request.POST.get("id")
        action = request.POST.get("action")
        emetteur = request.POST.get("emetteur")
        motifs = request.POST.get("motif_refus")

        if not all([produit_id, action, emetteur]):
            return JsonResponse(
                {"success": False, "message": "Données manquantes"}, status=400
            )

        try:
            demande = Demander.objects.get(id=produit_id)
        except Demander.DoesNotExist:
            return JsonResponse(
                {"success": False, "message": "Demande introuvable"},
                status=404
            )

        match action, emetteur:
            case "1", "chef":
                demande.valider_par_chef = True
            case "1", "logisticien":
                demande.valider_par_logisticien = True
            case "0", "chef":
                demande.valider_par_chef = False
            case "0", "logisticien":
                demande.valider_par_logisticien = False
                demande.motif_refus = motifs
            case _:
                return JsonResponse(
                    {"success": False, "message": "Données invalides"},
                    status=400
                )

        demande.save()
        return JsonResponse({"success": True, "message": "Statut mis à jour"})
    return JsonResponse(
        {"success": False, "message": "Méthode non autorisée"}, status=405
    )

@login_required(login_url="login")
def recuperer_liste_produit(request):
    """Récupèrez et renvoyez la liste des produits paginés.

    Parameters
    ----------
    request : HttpRequest
        La requête HTTP entrante.

    Returns
    -------
    HttpResponse
        La réponse HTTP contenant la page rendue avec la liste des produits.

    """
    liste_produit = Produit.objects.all().order_by("-id")
    pagination = Paginator(liste_produit, 8)

    page_number = request.GET.get("page")
    page_obj = pagination.get_page(page_number)

    return render(
        request,
        "gestion_produit/index.html",
        {"page_obj": page_obj}
    )

@login_required(login_url="login")
def enregistrer_categorie(request):
    """Enregistrez une nouvelle catégorie de produit.

    Cette vue est appelée via une requête AJAX avec la méthode POST et
    enregistre une nouvelle.

    Parameters
    ----------
    request : HttpRequest
        La requête HTTP entrante.

    Returns
    -------
    JsonResponse
        Réponse JSON indiquant le succès ou l'échec de l'enregistrement.

    """
    if request.method == "POST":
        categories = EnregistrementCategorie(request.POST)
        if categories.is_valid():
            categories.save()
            return JsonResponse({"success": True})
        return JsonResponse({"success": False})
    return None

@login_required(login_url="login")
def recuperer_fournisseur_par_categorie(_request, id_produit):
    """Récupèrez les fournisseurs associés à la catégorie d'un produit donné.

    Parameters
    ----------
    request : HttpRequest
        La requête HTTP entrante.
    id_produit : int
        L'ID du produit dont on veut récupérer les fournisseurs.

    Returns
    -------
    JsonResponse
        Réponse JSON contenant la liste des fournisseurs associés à la
        catégorie du produit.

    """
    produit = Produit.objects.get(id=id_produit)
    fournisseur = Fournisseur.objects.filter(categorie=produit.categorie)

    produit_founisseur = [
        {
            "id": fournisseur_produit.id,
            "nom_fournisseur": fournisseur_produit.nom_entreprise,
        }
        for fournisseur_produit in fournisseur
    ]

    return JsonResponse(produit_founisseur, safe=False)

def calcul_stock_produit(produit):
    """Calculez le stock actuel d'un produit donné.

    Parameters
    ----------
    produit : Produit
        L'instance du produit pour lequel calculer le stock.

    Returns
    -------
    dict
        Dictionnaire contenant les détails du produit et son stock actuel.

    """
    quantite_livrer = (
        Commander.objects.filter(livrer=True, produit=produit).aggregate(
            Sum("quantite_commander")
        )["quantite_commander__sum"]
        or 0
    )
    produit_demander_a_rendre = Demander.objects.filter(
        produit=produit,
        valider_par_logisticien=True,
    )

    quantite_produit_sortis = 0

    for produit_demander in produit_demander_a_rendre:
        if (
            (produit_demander.a_rendre and produit_demander.rendu is False)
            or produit_demander.a_rendre is False
        ):
            quantite_produit_sortis += produit_demander.quantite

    stock_actuel = (produit.quantite_stock
                    + quantite_livrer
                    - quantite_produit_sortis)
    return {
        "id": produit.id,
        "libelle": produit.libelle,
        "quantite_stock": produit.quantite_stock,
        "conditionnement": produit.conditionnement,
        "seuil_pre_rupture": produit.seuil_pre_rupture,
        "image": produit.image,
        "categorie_id": produit.categorie_id,
        "stockActuel": stock_actuel,
    }

@login_required(login_url="login")
def mouvement_stock(request):
    """Retournez la page de mouvement de stock.

    Parameters
    ----------
    request : HttpRequest
        La requête HTTP entrante.

    Returns
    -------
    HttpResponse
        La réponse HTTP contenant la page rendue.

    """
    return render(request, "gestion_produit/mouvement_stock.html")

@login_required(login_url="login")
def rapport_mouvement_stock(request):
    """Générez un rapport de mouvement de stock basé sur les filtres donnés.

    Parameters
    ----------
    request : HttpRequest
        La requête HTTP entrante.
        request.GET["dateFiltre"] : str
            La date de filtre au format "YYYY-MM".
        request.GET["typeFiltre"] : str
            Le type de filtre ("entree" ou "sortie").

    Returns
    -------
    JsonResponse
        Réponse JSON contenant le rapport de mouvement de stock.

    """
    mes_commandes = []
    date_filtre = request.GET["dateFiltre"]
    annee, mois = date_filtre.split("-")
    type_filtre = request.GET["typeFiltre"]

    if type_filtre == "entree":
        mes_commandes.extend([
            {
                "produit_entree": commande.produit.libelle,
                "categorie_entree": commande.produit.categorie.categorie,
                "conditionnement_entree": commande.produit.conditionnement,
                "fournisseur_entree": commande.fournisseur.nom_entreprise,
                "date_commande_entree": commande.date_commande,
                "date_livraison_entree": commande.date_livraison,
                "quantite_commander_entree": commande.quantite_commander,
            }
            for commande in Commander.objects.filter(
                date_livraison__year=annee,
                date_livraison__month=mois,
                livrer=True
            )
        ])

    elif type_filtre == "sortie":
        mes_commandes.extend([
            {
                "produit_sortie": demande.produit.libelle,
                "categorie_sortie": demande.produit.categorie.categorie,
                "conditionnement_sortie": demande.produit.conditionnement,
                "date_demande_sortie": demande.date_de_mise_a_dispo_souhaite,
                # "date_mise_a_dispo": commande.date_commande,
                "quantite_demander_sortie": demande.quantite,
            }
            for demande in Demander.objects.filter(
                date_de_mise_a_dispo_souhaite__year=annee,
                date_de_mise_a_dispo_souhaite__month=mois,
                valider_par_logisticien=True,
            )
        ])

    return JsonResponse(mes_commandes, safe=False)