"""Ce fichier contient les utilitaires du reporting"""
# import des pré requis
from ast import For
import json
from datetime import date
from logging import getLevelName
import time
import pandas as pd
from django.utils import timezone
from django.db.models import Sum
from .models import Administre, Domaine, FMOB, Fonction, FormationEmploi, Garnison, Grade, Poste, Notation, \
    PreferencesListe, Marque, MarquesGroupe, Filiere, Decision, SousVivier, SousVivierAssociation, \
    AvisPosteChoices as AvisPoste
from .utils_insertion import insert_Notation
import numpy as np

def reporting_taux_armement_pcp(fe_id, f_id, d_id, nf, categorie):
    """
    Renvoie les indicateurs figurant dans la vue Taux Armement FE pour les PCP

    :type fe_id: list
    :param fe_id: codes CREDO des FE sur lesquelles on filtre

    :type f_id: list
    :param f_id: trigrammes des filières sur lesquelles on filtre

    :type d_id: list
    :param d_id: trigrammes des domaines sur lesquels on filtre

    :type nf: list
    :param nf: niveau fonctionnel sur lesquels on filtre

    :type categorie: list
    :param categorie: catégorie sur lesquelles on filtre


    :return:    - **nb_militaires_actuel** (*int*): Nombre de militaires présents dans la/les FE selon les filtres cochés.
            - **nb_postes_actuel** (*int*): Nombre de postes présents dans la/les FE selon les filtres cochés.
            - **ecart_actuel** (*int*): Différence entre le nombre de postes et de militaires présents actuellement.
            - **taux_armement_actuel** (*int*): Taux d'armement de la/les FE selon les filtres cochés.
            - **nb_militaires_entrants** (*int*): Nombre de militaires entrants dans la FE selon les filtres cochés.
            - **nb_militaires_sortants** (*int*): Nombre de militaires sortants de la FE selon les filtres cochés.
            - **nb_militaires_projete** (*int*): Nombre de militaires attendus dans la FE après les mobilités selon les filtres cochés.
            - **taux_armement_projete** (*int*): Taux d'armement projete selon les filtres cochés.
            - **taux_armement_cible** (*int*): Taux d'armement cible pour la FE choisie selon la catégorie choisie, None si plusieurs catégories ont été sélectionnées.

    """
    taux_armement_cible = None
    if len(fe_id) == 1 and len(categorie) == 1:
        fe = FormationEmploi.objects.get(fe_code__in=fe_id)
        if 'MDR' in categorie:
            taux_armement_cible = fe.fe_taux_armement_cible_mdr
        if 'OFF' in categorie:
            taux_armement_cible = fe.fe_taux_armement_cible_off
        if 'SOFF' in categorie:
            taux_armement_cible = fe.fe_taux_armement_cible_soff

    nb_militaires_actuel = Administre.objects.filter(formation_emploi_id__in=fe_id, a_domaine__in=d_id, a_filiere__in=f_id, a_nf__in=nf, a_categorie__in=categorie).count() or 0
    nb_militaires_sortants = Administre.objects.filter(a_domaine_id__in=d_id, a_filiere_id__in=f_id, a_nf__in=nf, a_categorie__in=categorie, formation_emploi_id__in=fe_id, a_statut_pam__in=['A_MUTER', 'NON_DISPONIBLE', 'PARTANT']).count() or 0
    nb_militaires_entrants = Decision.objects.filter(administre__a_domaine_futur_id__in=d_id, administre__a_filiere_futur_id__in=f_id, administre__a_nf_futur__in=nf, administre__a_categorie__in=categorie, administre__formation_emploi_id__in=fe_id).count() or 0
    nb_militaires_projete = nb_militaires_actuel + nb_militaires_entrants - nb_militaires_sortants
    nb_postes_actuel = Poste.objects.filter(formation_emploi_id__in=fe_id, p_filiere__in=f_id, p_domaine__in=d_id, p_nf__in=nf, p_categorie__in=categorie).count() or 0
    if nb_postes_actuel == 0:
        nb_postes_actuel = 0
        taux_armement_actuel = 0
        taux_armement_projete = 0
    else:
        ecart_actuel = nb_postes_actuel - nb_militaires_actuel
        ecart_projete = nb_postes_actuel - nb_militaires_projete
        taux_armement_actuel = nb_militaires_actuel / nb_postes_actuel * 100
        taux_armement_projete = nb_militaires_projete / nb_postes_actuel * 100

    ecart_actuel = nb_postes_actuel - nb_militaires_actuel
    ecart_projete = nb_postes_actuel - nb_militaires_projete

    return nb_militaires_actuel, nb_postes_actuel, ecart_actuel, taux_armement_actuel, nb_militaires_entrants, nb_militaires_sortants, nb_militaires_projete, taux_armement_projete, taux_armement_cible

def reporting_taux_armement_gestionnaire(fe_id, f_id, d_id, nf, categorie, sv_id):
    """
    Renvoie les indicateurs figurant dans la vue Taux Armement FE pour les gestionnaires

    :type fe_id: list
    :param fe_id: codes CREDO des FE sur lesquelles on filtre

    :type f_id: list
    :param f_id: trigrammes des filières sur lesquelles on filtre

    :type d_id: list
    :param d_id: trigrammes des domaines sur lesquels on filtre

    :type nf: list
    :param nf: niveau fonctionnel sur lesquels on filtre

    :type sv_id: chaine de caractères
    :param categorie: sous-vivier du gestionnaire

    :type categorie: list
    :param categorie: catégorie sur lesquelles on filtre


    :return:    - **nb_militaires_actuel** (*int*): Nombre de militaires présents dans la/les FE selon les filtres cochés.
        - **nb_postes_actuel** (*int*): Nombre de postes présents dans la/les FE selon les filtres cochés.
        - **ecart_actuel** (*int*): Différence entre le nombre de postes et de militaires présents actuellement.
        - **taux_armement_actuel** (*int*): Taux d'armement de la/les FE selon les filtres cochés.
        - **nb_militaires_entrants** (*int*): Nombre de militaires entrants dans la FE selon les filtres cochés.
        - **nb_militaires_sortants** (*int*): Nombre de militaires sortants de la FE selon les filtres cochés.
        - **nb_militaires_projete** (*int*): Nombre de militaires attendus dans la FE après les mobilités selon les filtres cochés.
        - **taux_armement_projete** (*int*): Taux d'armement projete selon les filtres cochés.
        - **taux_armement_cible** (*int*): Taux d'armement cible pour la FE choisie selon la catégorie choisie, None si plusieurs catégories ont été sélectionnées.


    """
    taux_armement_cible = None
    if len(fe_id) == 1 and len(categorie) == 1:
        fe = FormationEmploi.objects.get(fe_code__in=fe_id)
        if 'MDR' in categorie:
            taux_armement_cible = fe.fe_taux_armement_cible_mdr
        if 'OFF' in categorie:
            taux_armement_cible = fe.fe_taux_armement_cible_off
        if 'SOFF' in categorie:
            taux_armement_cible = fe.fe_taux_armement_cible_soff

    nb_militaires_actuel = Administre.objects.filter(sous_vivier_id=sv_id, formation_emploi_id__in=fe_id, a_domaine__in=d_id, a_filiere__in=f_id, a_nf__in=nf, a_categorie__in=categorie).count() or 0
    nb_militaires_sortants = Administre.objects.filter(sous_vivier_id=sv_id, a_domaine_id__in=d_id, a_filiere_id__in=f_id, a_nf__in=nf, a_categorie__in=categorie, formation_emploi_id__in=fe_id, a_statut_pam__in=['A_MUTER', 'NON_DISPONIBLE', 'PARTANT']).count() or 0
    nb_militaires_entrants = Decision.objects.filter(administre__a_domaine_futur_id__in=d_id, administre__a_filiere_futur_id__in=f_id, administre__a_nf_futur__in=nf, administre__a_categorie__in=categorie, administre__formation_emploi_id__in=fe_id).count() or 0
    nb_militaires_projete = nb_militaires_actuel + nb_militaires_entrants - nb_militaires_sortants
    nb_postes_actuel = Poste.objects.filter(sous_viviers=sv_id, formation_emploi_id__in=fe_id, p_filiere__in=f_id, p_domaine__in=d_id, p_nf__in=nf, p_categorie__in=categorie).count() or 0
    if nb_postes_actuel == 0:
        nb_postes_actuel = 0
        taux_armement_actuel = 0
        taux_armement_projete = 0
    else:
        ecart_actuel = nb_postes_actuel - nb_militaires_actuel
        ecart_projete = nb_postes_actuel - nb_militaires_projete
        taux_armement_actuel = nb_militaires_actuel / nb_postes_actuel * 100
        taux_armement_projete = nb_militaires_projete / nb_postes_actuel * 100

    ecart_actuel = nb_postes_actuel - nb_militaires_actuel
    ecart_projete = nb_postes_actuel - nb_militaires_projete

    return nb_militaires_actuel, nb_postes_actuel, ecart_actuel, taux_armement_actuel, nb_militaires_entrants, nb_militaires_sortants, nb_militaires_projete, taux_armement_projete, taux_armement_cible


def reporting_suivi_pam_admin(sv_id, f_id, d_id, nf, categorie):
    """
    Renvoie les indicateurs figurant dans la vue Suivi PAM gestionnaire pour les administrés

    :type f_id: list
    :param f_id: trigrammes des filières sur lesquelles on filtre

    :type d_id: list
    :param d_id: trigrammes des domaines sur lesquels on filtre

    :type nf: list
    :param nf: niveau fonctionnel sur lesquels on filtre

    :type sv_id: chaine de caractères
    :param categorie: sous-vivier du gestionnaire

    :type categorie: list
    :param categorie: catégorie sur lesquelles on filtre


    :return:    - **nb_a_etudier** (*int*): Nombre de militaires à étudier selon les filtres cochés.
            - **nb_a_muter** (*int*): Nombre de militaires à muter selon les filtres cochés.
            - **nb_a_maintenir** (*int*): Nombre de militaires à maintenir selon les filtres cochés.
            - **nb_non_etudie_administres** (*int*): Nombre de militaires non étudiés selon les filtres cochés.
            - **nb_a_partant** (*int*): Nombre de militaires partant selon les filtres cochés.
            - **nb_a_non_dispo** (*int*): Nombre de militaires non disponibles selon les filtres cochés.
            - **nb_prepos_administres** (*int*): Nombre de militaires prépositionnés selon les filtres cochés.
            - **nb_pos_administres** (*int*): Nombre de militaires positionnés selon les filtres cochés.
            - **nb_omi_active_administres** (*int*): Nombre de militaires avec un OMI activé selon les filtres cochés.
            - **nb_omi_en_cours_administres** (*int*): Nombre de militaires avec un OMI en cours selon les filtres cochés.
            - **reste_a_realiser_administres** (*int*): Nombre de militaires à muter ou à étudier pour lesquels aucune décision n'a été prise.
            - **reste_a_realiser_a_etudier** (*int*): Nombre de militaires à étudier pour lesquels aucune décision n'a été prise.
            - **reste_a_realiser_a_muter** (*int*): Nombre de militaires à muter pour lesquels aucune décision n'a été prise.


    """
    nb_militaires_fe = Administre.objects.filter(a_domaine_futur_id__in=d_id, a_filiere_futur_id__in=f_id, a_nf_futur__in=nf, a_categorie__in=categorie).count()

    a_etudier = Administre.objects.filter(sous_vivier_id=sv_id, a_domaine_futur_id__in=d_id, a_filiere_futur_id__in=f_id, a_nf_futur__in=nf, a_categorie__in=categorie, a_statut_pam="A_ETUDIER")
    a_muter = Administre.objects.filter(sous_vivier_id=sv_id, a_domaine_futur_id__in=d_id, a_filiere_futur_id__in=f_id, a_nf_futur__in=nf, a_categorie__in=categorie, a_statut_pam="A_MUTER")
    a_maintenir = Administre.objects.filter(sous_vivier_id=sv_id, a_domaine_futur_id__in=d_id, a_filiere_futur_id__in=f_id, a_nf_futur__in=nf, a_categorie__in=categorie, a_statut_pam="A_MAINTENIR")
    non_etudie_administres = Administre.objects.filter(sous_vivier_id=sv_id, a_domaine_futur_id__in=d_id, a_filiere_futur_id__in=f_id, a_nf_futur__in=nf, a_categorie__in=categorie, a_statut_pam="NON_ETUDIE")
    a_partant = Administre.objects.filter(sous_vivier_id=sv_id, a_domaine_futur_id__in=d_id, a_filiere_futur_id__in=f_id, a_nf_futur__in=nf, a_categorie__in=categorie, a_statut_pam="PARTANT")
    a_non_dispo = Administre.objects.filter(sous_vivier_id=sv_id, a_domaine_futur_id__in=d_id, a_filiere_futur_id__in=f_id, a_nf_futur__in=nf, a_categorie__in=categorie, a_statut_pam="NON_DISPONIBLE")
    nb_a_etudier = a_etudier.count() or 0
    nb_a_muter = a_muter.count() or 0
    nb_a_maintenir = a_maintenir.count() or 0
    nb_non_etudie_administres = non_etudie_administres.count() or 0
    nb_a_partant = a_partant.count() or 0
    nb_a_non_dispo = a_non_dispo.count() or 0
    nb_prepos_administres = Decision.objects.filter(administre__a_domaine_futur_id__in=d_id, administre__a_filiere_futur_id__in=f_id, administre__a_nf_futur__in=nf, administre__a_categorie__in=categorie, administre__sous_vivier_id=sv_id, administre__a_statut_pam__in=["A_ETUDIER", "A_MUTER"], de_decision='PREPOSITIONNE').count() or 0
    nb_pos_administres = Decision.objects.filter(administre__a_domaine_futur_id__in=d_id, administre__a_filiere_futur_id__in=f_id, administre__a_nf_futur__in=nf, administre__a_categorie__in=categorie, administre__sous_vivier_id=sv_id, administre__a_statut_pam__in=["A_ETUDIER", "A_MUTER"], de_decision='POSITIONNE').count() or 0
    nb_omi_active_administres = Decision.objects.filter(administre__a_domaine_futur_id__in=d_id, administre__a_filiere_futur_id__in=f_id, administre__a_nf_futur__in=nf, administre__a_categorie__in=categorie, administre__sous_vivier_id=sv_id, administre__a_statut_pam__in=["A_ETUDIER", "A_MUTER"], de_decision='OMI_ACTIVE').count() or 0
    nb_omi_en_cours_administres = Decision.objects.filter(administre__a_domaine_futur_id__in=d_id, administre__a_filiere_futur_id__in=f_id, administre__a_nf_futur__in=nf, administre__a_categorie__in=categorie, administre__sous_vivier_id=sv_id, administre__a_statut_pam__in=["A_ETUDIER", "A_MUTER"], de_decision='OMI_EN_COURS').count() or 0
    reste_a_realiser_a_etudier = nb_a_etudier - Decision.objects.filter(administre__a_domaine_futur_id__in=d_id, administre__a_filiere_futur_id__in=f_id, administre__a_nf_futur__in=nf, administre__a_categorie__in=categorie, administre__sous_vivier_id=sv_id, administre__a_statut_pam="A_ETUDIER").count() or 0
    reste_a_realiser_a_muter = nb_a_muter - Decision.objects.filter(administre__a_domaine_futur_id__in=d_id, administre__a_filiere_futur_id__in=f_id, administre__a_nf_futur__in=nf, administre__a_categorie__in=categorie, administre__sous_vivier_id=sv_id, administre__a_statut_pam="A_MUTER").count() or 0
    reste_a_realiser_administres = (nb_a_etudier + nb_a_muter) - (nb_prepos_administres + nb_pos_administres + nb_omi_en_cours_administres + nb_omi_active_administres)

    return nb_a_etudier, nb_a_muter, nb_a_maintenir, nb_non_etudie_administres, nb_a_partant, nb_a_non_dispo, nb_prepos_administres, nb_pos_administres, nb_omi_active_administres, nb_omi_en_cours_administres, reste_a_realiser_administres, reste_a_realiser_a_etudier, reste_a_realiser_a_muter


def reporting_suivi_pam_poste(sv_id, f_id, d_id, nf, categorie):
    """
    Renvoie les indicateurs figurant dans la vue Suivi PAM gestionnaire pour les postes

    :type f_id: list
    :param f_id: trigrammes des filières sur lesquelles on filtre

    :type d_id: list
    :param d_id: trigrammes des domaines sur lesquels on filtre

    :type nf: list
    :param nf: niveau fonctionnel sur lesquels on filtre

    :type sv_id: chaine de caractères
    :param categorie: sous-vivier du gestionnaire

    :type categorie: list
    :param categorie: catégorie sur lesquelles on filtre

    :return:    - **nb_p1** (*int*): Nombre de postes P1 selon les filtres cochés.
            - **nb_p2** (*int*): Nombre de postes P2 selon les filtres cochés.
            - **nb_p3** (*int*): Nombre de postes P3 selon les filtres cochés.
            - **nb_p4** (*int*): Nombre de postes P4 selon les filtres cochés.
            - **nb_gele** (*int*): Nombre de postes gelés selon les filtres cochés.
            - **nb_non_etudie_postes** (*int*): Nombre de postes non étudiés selon les filtres cochés.
            - **nb_prepos_postes** (*int*): Nombre de postes prépositionnés selon les filtres cochés.
            - **nb_pos_postes** (*int*): Nombre de postes positionnés selon les filtres cochés.
            - **nb_omi_active_postes** (*int*): Nombre de postes avec un OMI activé selon les filtres cochés.
            - **nb_omi_en_cours_postes** (*int*): Nombre de postes avec un OMI en cours selon les filtres cochés.
            - **reste_a_realiser_postes** (*int*): Nombre de postes de P1 à P4 pour lesquels aucune décision n'a été prise.
            - **reste_a_realiser_p1** (*int*): Nombre de postes P1 pour lesquels aucune décision n'a été prise.
            - **reste_a_realiser_p2** (*int*): Nombre de postes P2 pour lesquels aucune décision n'a été prise.
            - **reste_a_realiser_p3** (*int*): Nombre de postes P3 pour lesquels aucune décision n'a été prise.
            - **reste_a_realiser_p4** (*int*): Nombre de postes P4 pour lesquels aucune décision n'a été prise.



    """
    nb_p1 = Poste.objects.filter(sous_viviers=sv_id, p_domaine__in=d_id, p_filiere__in=f_id, p_nf__in=nf, p_categorie__in=categorie, p_avis=AvisPoste.P1).count() or 0
    nb_p2 = Poste.objects.filter(sous_viviers=sv_id, p_domaine__in=d_id, p_filiere__in=f_id, p_nf__in=nf, p_categorie__in=categorie, p_avis=AvisPoste.P2).count() or 0
    nb_p3 = Poste.objects.filter(sous_viviers=sv_id, p_domaine__in=d_id, p_filiere__in=f_id, p_nf__in=nf, p_categorie__in=categorie, p_avis=AvisPoste.P3).count() or 0
    nb_p4 = Poste.objects.filter(sous_viviers=sv_id, p_domaine__in=d_id, p_filiere__in=f_id, p_nf__in=nf, p_categorie__in=categorie, p_avis=AvisPoste.P4).count() or 0
    nb_gele = Poste.objects.filter(sous_viviers=sv_id, p_domaine__in=d_id, p_filiere__in=f_id, p_nf__in=nf, p_categorie__in=categorie, p_avis=AvisPoste.GELE).count() or 0
    nb_non_etudie_postes = Poste.objects.filter(sous_viviers=sv_id, p_domaine__in=d_id, p_filiere__in=f_id, p_nf__in=nf, p_categorie__in=categorie, p_avis=AvisPoste.NON_ETUDIE).count() or 0



    nb_prepos_postes = Decision.objects.filter(poste__p_domaine__in=d_id, poste__p_filiere__in=f_id, poste__p_nf__in=nf, poste__p_categorie__in=categorie, poste__sous_viviers=sv_id, de_decision='PREPOSITIONNE').count() or 0
    nb_pos_postes = Decision.objects.filter(poste__p_domaine__in=d_id, poste__p_filiere__in=f_id, poste__p_nf__in=nf, poste__p_categorie__in=categorie, poste__sous_viviers=sv_id, de_decision='POSITIONNE').count() or 0
    nb_omi_active_postes = Decision.objects.filter(poste__p_domaine__in=d_id, poste__p_filiere__in=f_id, poste__p_nf__in=nf, poste__p_categorie__in=categorie, poste__sous_viviers=sv_id, de_decision='OMI_ACTIVE').count() or 0
    nb_omi_en_cours_postes = Decision.objects.filter(poste__p_domaine__in=d_id, poste__p_filiere__in=f_id, poste__p_nf__in=nf, poste__p_categorie__in=categorie, poste__sous_viviers=sv_id, de_decision='OMI_EN_COURS').count() or 0

    reste_a_realiser_p1 = 0
    reste_a_realiser_p2 = 0
    reste_a_realiser_p3 = 0
    reste_a_realiser_p4 = 0
    reste_a_realiser_postes = (nb_p1 + nb_p2 + nb_p3 + nb_p4) - (nb_prepos_postes + nb_pos_postes + nb_omi_active_postes + nb_omi_en_cours_postes)
    if reste_a_realiser_postes > nb_p4:
        reste_a_realiser_p4 = nb_p4
        if reste_a_realiser_postes - nb_p4 > nb_p3:
            reste_a_realiser_p3 = nb_p3
            if reste_a_realiser_postes - nb_p4 - nb_p3 > nb_p2:
                reste_a_realiser_p2 = nb_p2
                if reste_a_realiser_postes - nb_p4 - nb_p3 - nb_p2 >= nb_p1:
                    reste_a_realiser_p1 = nb_p1
                else:
                    reste_a_realiser_p1 = reste_a_realiser_postes - nb_p4 - nb_p3 - nb_p2
            else:
                reste_a_realiser_p2 = reste_a_realiser_postes - nb_p4 - nb_p3
                reste_a_realiser_p1 = 0
        else:
            reste_a_realiser_p3 = reste_a_realiser_postes - nb_p4
            reste_a_realiser_p2 = 0
            reste_a_realiser_p1 = 0
    else:
        reste_a_realiser_p4 = nb_p4 - reste_a_realiser_postes
        reste_a_realiser_p2 = 0
        reste_a_realiser_p3 = 0
        reste_a_realiser_p4 = 0


    return nb_p1, nb_p2, nb_p3, nb_p4, nb_gele, nb_non_etudie_postes, reste_a_realiser_postes, reste_a_realiser_p1, reste_a_realiser_p2, reste_a_realiser_p3, reste_a_realiser_p4, nb_prepos_postes, nb_pos_postes, nb_omi_active_postes, nb_omi_en_cours_postes

# TODO : Supprimer cette fonction car non utilisée dans le code et utilise SousvivierAssociation
def poste_vacant_vivier(sv_id, fe_id):
    """
    Renvoie le nombre de postes vacants dans un sous-vivier pour une FE sélectionnée

    :type sv_id: chaine de caractères
    :param sv_id: sous-vivier du gestionnaire

    :type fe_id: chaine de caractères
    :param fe_id: FE sur laquelle le gestionnaire a filtré

    :return:    - **1** (*int*): Nombre de postes vacants pour la FE sélectionnée.



    """
    sva = SousVivierAssociation.objects.filter(sous_vivier_id=sv_id).first()
    categorie = sva.sva_categorie
    fe = FormationEmploi.objects.get(fe_code=fe_id)

    if categorie == 'MDR':
        nb_poste_reevalue_fe = fe.fe_nb_poste_reevalue_mdr or 0
        nb_poste_vacant_fe = fe.fe_nb_poste_vacant_mdr or 0
    if categorie == 'OFF':
        nb_poste_reevalue_fe = fe.fe_nb_poste_reo_off or 0
        nb_poste_vacant_fe = fe.fe_nb_poste_vacant_off or 0
    if categorie == 'SOFF':
        nb_poste_reevalue_fe = fe.fe_nb_poste_reevalue_soff or 0
        nb_poste_vacant_fe = fe.fe_nb_poste_vacant_soff or 0

    nb_poste_vivier_dans_fe = Poste.objects.filter(formation_emploi_id=fe_id, sous_viviers=sv_id).aggregate(Sum('p_id')) or 0
    if nb_poste_reevalue_fe == 0:
        return 0
    else:
        proportion = nb_poste_vivier_dans_fe / nb_poste_reevalue_fe
        nb_poste_vacant_vivier = proportion * nb_poste_vacant_fe
        if nb_poste_vacant_vivier > np.floor(nb_poste_vacant_vivier) + 0.5:
            return np.ceil(nb_poste_vacant_vivier)
        else:
            return np.floor(nb_poste_vacant_vivier)
