"""
Ce module contient les Utilitaires du backend
"""
from datetime import datetime
from random import randint
import re
from django.forms import model_to_dict
from backend import constants
from backend.models import Administre, Poste, SousVivier, FormationEmploi, RefSvFil, SousVivierAssociation
import pandas as pd
import numpy as np


def nf2categorie(nf: str) -> str:
    """
    Renvoie la catégorie associé au niveau fonctionnel en argument

    :type nf: str
    :param nf: niveau fonctionnel

    :return: catégorie associée au niveau fonctionnel
    :rtype: str
    """
    list_mdr  = ['1A', '1B', '1C']
    list_soff = ['2.', '3A', '3B', '3B NFS']
    list_off  = ['4.', '5A', '5B', '5C', '6A', '6B']
    cat = 'MDR' if nf in list_mdr else 'SOFF' if nf in list_soff else 'OFF' if nf in list_off else None
    return cat


def generate_sv_id(dom: str, fil: str, cat: str) -> str:
    """
    Génère un id de sous-vivier à partir d'un domaine, d'une filière et d'une catégorie.

    :type dom: str
    :param dom: domaine du sous-vivier

    :type fil: str
    :param fil: filiere du sous-vivier

    :type cat: str
    :param cat: catégorie du sous-vivier

    :return: id du sous-vivier
    :rtype: str
    """
    return f"{dom}, {fil}, {cat}"


def sous_viviers_du_cellule(cellule_code):
    # Récupère les sous-viviers associés à la cellule
    sous_vivier = RefSvFil.objects.filter(ref_sv_fil_code=cellule_code)
    if sous_vivier.exists():
        sous_viviers = list(sous_vivier.values_list('sous_vivier_id', flat=True))
    else :
        return []
    return sous_viviers


def without_keys(d, keys):
    """
    Suppression des clés d'un dictionnaire

    :type d: Dictionnaire
    :param d: Dictionnaire contenant les ids

    :type keys: String
    :param keys: Les clés que nous devons supprimer du dictionnaire

    :return:    - **Dictionnaire** (*Dictionnaire*): Dictionnaire sans les clés données en argument.
    """
    return {x: d[x] for x in d if x not in keys}

def check_positive(valeur_nb):
    """
    Vérifier si une valeur est positive et retourner 1, si elle est nulle ou négative retourner 0.

    :type poste_nb: DataFrame
    :param poste_nb: ID du sous-vivier

    :return:    - **valeur_nb_modifie** (*dataframe*): Dataframe contenant des valeurs 1 ou 0.
    """
    valeur_nb_modifie = valeur_nb.apply(lambda x: 1 if x > 0 else 0)
    return valeur_nb_modifie

def cleanString(string):
    """Cette fonction supprimera tous les caractères qui ne sont pas alphanumériques.

    :type string: chaîne de caractères
    :param string: chaîne qui doit être nettoyée

    :return:    - **return** (*chaîne de caractères*): chaîne nettoyée.
    """
    return ''.join([i for i in string if i.isalnum()])


def intOrNone(value):
    """Cette fonction renvoie l'entier de la valeur ou renvoie None.

    :type value: float
    :param value: valeur a con

    :return:    - **res** (*int or None*): valeur à convertir.
    """
    try:
        res = int(float(value))
    except Exception:
        res = None

    return res

def impact_decisions(old_administre, administre, old_avis, avis, eip, fe_code, categorie):
    """

    :type administre: objet
    :param administre: instance du model Administre

    :type old_avis: chaine de caractères
    :param old_avis: avis de l'administré avant la mise à jour

    :type avis: chaine de caractère
    :param avis: nouvel avis de l'administré

    :type eip: chaine de caractère
    :param eip: eip actuel du militaire

    :type categorie: dataframe pandas
    :param categorie: Dataframe contenant les données pretraités à inserer

    :return:    - **list_error** (*liste*): liste des identifiants SAP pour lesquels il y a eu une erreur.
    """

    list_error = []
    if (old_avis == 'NON_ETUDIE' or old_avis == 'A_MAINTENIR' or old_avis == 'A_ETUDIER') and (avis == 'A_MUTER' or avis == 'PARTANT' or avis == 'NON_DISPONIBLE'):
        poste_qs = Poste.objects.filter(p_eip__iexact=eip, formation_emploi_id=fe_code)
        poste = poste_qs.first()
        fe = FormationEmploi.objects.get(fe_code=fe_code)
        fe.save()

        if poste and poste.p_nb_non_etudie > 0:
            new_nb_p4, new_nb_non_etudie, new_nb_vacant, new_nb_occupe = poste.p_nb_p4 + 1, poste.p_nb_non_etudie - 1, poste.p_nb_vacant + 1, poste.p_nb_occupe - 1
            poste_qs.update(p_nb_p4=new_nb_p4, p_nb_non_etudie=new_nb_non_etudie,
                            p_nb_vacant=new_nb_vacant,
                            p_nb_occupe=new_nb_occupe)

        else:
            list_error.append(administre.a_id_sap)

    if (old_avis == 'A_MUTER' or old_avis == 'PARTANT' or old_avis == 'NON_DISPONIBLE') and (avis == 'NON_ETUDIE' or avis == 'A_MAINTENIR' or avis == 'A_ETUDIER'):
        poste_qs = Poste.objects.filter(p_eip__iexact=eip, formation_emploi_id=fe_code).exclude(p_nb_occupe=0)
        poste = poste_qs.first()
        fe = FormationEmploi.objects.get(fe_code=fe_code)
        if categorie == constants.CATEGORIE_MDR:
            fe.fe_nb_poste_vacant_mdr = fe.fe_nb_poste_vacant_mdr - 1
            fe.fe_nb_poste_occupe_mdr = fe.fe_nb_poste_occupe_mdr + 1
        elif categorie == constants.CATEGORIE_SOFF:
            fe.fe_nb_poste_vacant_soff = fe.fe_nb_poste_vacant_soff - 1
            fe.fe_nb_poste_occupe_soff = fe.fe_nb_poste_occupe_soff + 1
        elif categorie == constants.CATEGORIE_OFF:
            fe.fe_nb_poste_vacant_off = fe.fe_nb_poste_vacant_off - 1
            fe.fe_nb_poste_occupe_off = fe.fe_nb_poste_occupe_off + 1

        fe.save()

        if poste and poste.p_nb_p4 > 0:
            new_nb_p4, new_nb_non_etudie, new_nb_vacant, new_nb_occupe = poste.p_nb_p4 - 1, poste.p_nb_non_etudie + 1, poste.p_nb_vacant - 1, poste.p_nb_occupe + 1
            poste_qs.update(p_nb_p4=new_nb_p4, p_nb_non_etudie=new_nb_non_etudie,
                            p_nb_vacant=new_nb_vacant,
                            p_nb_occupe=new_nb_occupe)
        if poste and poste.p_nb_p4 == 0 and poste.p_nb_p3 > 0:
            new_nb_p3, new_nb_non_etudie, new_nb_vacant, new_nb_occupe = poste.p_nb_p3 - 1, poste.p_nb_non_etudie + 1, poste.p_nb_vacant - 1, poste.p_nb_occupe + 1
            poste_qs.update(p_nb_p3=new_nb_p3, p_nb_non_etudie=new_nb_non_etudie,
                            p_nb_vacant=new_nb_vacant,
                            p_nb_occupe=new_nb_occupe)
        if poste and poste.p_nb_p4 == 0 and poste.p_nb_p3 == 0 and poste.p_nb_p2 > 0:
            new_nb_p2, new_nb_non_etudie, new_nb_vacant, new_nb_occupe = poste.p_nb_p2 - 1, poste.p_nb_non_etudie + 1, poste.p_nb_vacant - 1, poste.p_nb_occupe + 1
            poste_qs.update(p_nb_p2=new_nb_p2, p_nb_non_etudie=new_nb_non_etudie,
                            p_nb_vacant=new_nb_vacant,
                            p_nb_occupe=new_nb_occupe)
        if poste and poste.p_nb_p4 == 0 and poste.p_nb_p3 == 0 and poste.p_nb_p2 == 0 and poste.p_nb_p1 > 0:
            new_nb_p1, new_nb_non_etudie, new_nb_vacant, new_nb_occupe = poste.p_nb_p1 - 1, poste.p_nb_non_etudie + 1, poste.p_nb_vacant - 1, poste.p_nb_occupe + 1
            poste_qs.update(p_nb_p1=new_nb_p1, p_nb_non_etudie=new_nb_non_etudie,
                            p_nb_vacant=new_nb_vacant,
                            p_nb_occupe=new_nb_occupe)
        else:
            list_error.append(administre.a_id_sap)
        return list_error
