import time

from django.db.transaction import atomic
from django.http import Http404
from rest_framework.exceptions import APIException
from rest_framework.permissions import IsAdminUser, IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView

from ..serializers import AlimentationRefsDroitSerializer
from ..utils.alimentation_decorators import (data_perf_logger_factory,
                                             get_data_logger)
from ..utils.decorators import execution_time, query_count
from ..utils_extraction import (DataFrameTypes, FileTypes, read_files_by_type,
                                to_table_fe, to_table_ref_gest,
                                to_table_ref_org, to_table_ref_sv_fil,
                                to_table_sous_vivier)
from ..utils_insertion import (insert_FormationEmploi, insert_RefFeMere,
                               insert_RefGest, insert_RefOrg, insert_RefSvFil,
                               insert_SousVivier, insert_SousVivier_instances,
                               update_m2m_links_gestionnaire)


class AlimentationReferentielsDroitView(APIView):
    """
    Page d'alimentation des référentiels destinés à la gestion des droits.
    - Chargement des sous-viviers via le référentiel sous-viviers/flières,
    - Chargement des référentiels gestionnaires, organique, sous-viviers/filières et FE,
    - Chargement des liens entre les formation-emplois et les gestionnaires suivant la gestion de droits mise en place,
    - Chargement des liens entre les sous-viviers et les gestionnaires suivant la gestion de droits mise en place,
    - Attribution des sous-viviers aux postes et aux administrés.
    """

    permission_classes = [IsAuthenticated, IsAdminUser]
    serializer_class = AlimentationRefsDroitSerializer

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.logger = get_data_logger(self)


    def get(self, request):
        return Response("Formulaire d'alimentation d'OGURE NG pour les référentiels destinés à la gestion des droits")


    @atomic
    @execution_time(logger_factory=data_perf_logger_factory)
    @query_count(logger_factory=data_perf_logger_factory)
    def post(self, request):
        """
        Charge le(s) fichier(s) et met à jour la base.

        :param request: requête, contient les fichiers
        :type  request: class:`rest_framework.request.Request`

        :raises: class:`rest_framework.exceptions.APIException`

        :return: réponse
        :rtype:  class:`rest_framework.response.Response`
        """
        try:
            validator = self.serializer_class(data=request.data)
            validator.is_valid(raise_exception=True)

            df_by_type = read_files_by_type({
                FileTypes.REF_FE:     validator.validated_data.get('referentiel_fe'),
                FileTypes.REF_GEST:   validator.validated_data.get('referentiel_gestionnaire'),
                FileTypes.REF_ORG:    validator.validated_data.get('referentiel_organique'),
                FileTypes.REF_SV_FIL: validator.validated_data.get('refeferentiel_sous_vivier_filiere'),
            })
            DF = DataFrameTypes
            ref_fe_df = df_by_type.get(DF.REF_FE)
            ref_gest_df = df_by_type.get(DF.REF_GEST)
            ref_org_df = df_by_type.get(DF.REF_ORG)
            ref_sv_fil_df = df_by_type.get(DF.REF_SV_FIL)

            self.logger.info('-------------------- Insert beginning ---------------------')
            start_time_insert = time.time()

            if ref_sv_fil_df is not None:
                df = to_table_sous_vivier(ref_sv_fil_df)
                self.logger.info('Extraction des données de sous-viviers                             ------> Succès')
                insert_SousVivier(df)
                self.logger.info('Insertion des sous-viviers                                         ------> Succès')
            else:
                self.logger.info('Mise à jour ignorée : sous-viviers (nécessite %s)', DF.REF_SV_FIL.value[1])

            if ref_org_df is not None:
                df = to_table_ref_org(ref_org_df)
                self.logger.info('Extraction des données du référentiel organique DRHAT              ------> Succès')
                insert_RefOrg(df)
                self.logger.info('Insertion du référentiel organique                                 ------> Succès')
            else:
                self.logger.info('Mise à jour ignorée : référentiel organique')

            if ref_gest_df is not None:
                df = to_table_ref_gest(ref_gest_df)
                self.logger.info('Extraction des données de gestionnaires DRHAT                      ------> Succès')
                insert_RefGest(df)
                self.logger.info('Insertion du référentiel gestionnaire / utilisateurs               ------> Succès')
            else:
                self.logger.info('Mise à jour ignorée : référentiel de gestionnaires')

            if ref_sv_fil_df is not None:
                df = to_table_ref_sv_fil(ref_sv_fil_df)
                self.logger.info('Extraction des données du référentiel de sous-viviers/filières     ------> Succès')
                insert_RefSvFil(df)
                self.logger.info('Insertion du référentiel de sous-viviers/filières                  ------> Succès')
            else:
                self.logger.info('Mise à jour ignorée : référentiel de sous-viviers/filières')

            if ref_gest_df is not None or ref_org_df is not None or ref_sv_fil_df is not None:
                update_m2m_links_gestionnaire('SV')
                self.logger.info('Insertion des liens M2M entre sous-viviers et gestionnaires        ------> Succès')
            else:
                self.logger.info('Mise à jour ignorée : liens gestionnaires/sous-viviers (nécessite %s ou %s ou %s)',
                                 DF.REF_GEST.value[1], DF.REF_ORG.value[1], DF.REF_SV_FIL.value[1])

            if ref_fe_df is not None:
                df = to_table_fe(ref_fe_df)
                self.logger.info('Extraction des données du référentiel FE                           ------> Succès')
                insert_FormationEmploi(df)
                self.logger.info('Insertion du référentiel FE                                        ------> Succès')
            else:
                self.logger.info('Mise à jour ignorée : formations-emplois (nécessite %s)', DF.REF_FE.value[1])

            if ref_fe_df is not None:
                insert_RefFeMere(ref_fe_df)
                self.logger.info('Référentiel FE mère                                                ------> Succès')
            else:
                self.logger.info('Mise à jour ignorée : formations-emplois mères (nécessite %s)', DF.REF_FE.value[1])

            if ref_gest_df is not None or ref_org_df is not None or ref_fe_df is not None:
                update_m2m_links_gestionnaire('FE')
                self.logger.info('Insertion des liens M2M entre formations-emplois et gestionnaires  ------> Succès')
            else:
                self.logger.info('Mise à jour ignorée : liens gestionnaires/formations-emplois (nécessite %s ou %s ou %s)',
                                 DF.REF_GEST.value[1], DF.REF_ORG.value[1], DF.REF_FE.value[1])

            # TODO if ....
            insert_SousVivier_instances()
            self.logger.info('Insertion des liens entre sous-vivivers et administrés/postes      ------> Succès')

            self.logger.debug('--------------- Insert time : %d seconds -----------------', time.time() - start_time_insert)
            self.logger.info('---------------------- Insert ending ----------------------')

            return Response({'Insertion réussie'})
        except (Http404, APIException):
            raise
        except BaseException:
            message = "Impossible d'alimenter les référentiels"
            self.logger.exception(message)
            raise APIException(message)
