"""
La classe Admin est la représentation d’un modèle dans l’interface d’administration
"""

import numpy as np
from django.contrib import admin, messages
from django.contrib.admin import helpers
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.forms import UserChangeForm, UserCreationForm
from django.db.models import (ManyToManyField, ManyToManyRel, ManyToOneRel,
                              OneToOneRel)
from django.http import HttpResponseRedirect
from django.shortcuts import render

from backend.form import GroupeFeForm, PcpFeGroupeForm, TauxArmementForm

from .models import (FMOB, Administre, Calcul, Competence, CustomUser, Decision,
                     Filiere, FormationEmploi, GroupeFe, Marque, MarquesGroupe,
                     Notation, PcpFeGroupe, Poste, PreferencesListe,
                     SousVivier, SousVivierAssociation, ZoneGeographique,
                     RefGest, RefOrg, RefSvFil, FichiersExporte)


def is_not_many_to(field):
    """ Vérifie qu'il ne s'agit ni d'un champ many-to-one ni d'un champ many-to-many """
    return not isinstance(field, ManyToManyField) and not isinstance(field, ManyToManyRel) and (not isinstance(field, ManyToOneRel) or isinstance(field, OneToOneRel))

def default_list_display(modelType):
    """ Retourne une liste de champs pour l'attribut list_display """
    pk = modelType._meta.pk.name
    fields = [field.name for field in modelType._meta.get_fields() if field.name != pk and is_not_many_to(field)]
    fields.insert(0, pk)
    return fields


class AdministreAdmin(admin.ModelAdmin):
    """Cette classe est dédiée à la section des administrés dans la page d'admin du projet.
     list_display va spécifier tous les champs des administrés qui doivent être affichés dans cette section dans la page admin.

    """
    list_display = default_list_display(Administre)


class CalculAdmin(admin.ModelAdmin):
    """Cette classe est dédiée à la section des administrés dans la page d'admin du projet.
     list_display va spécifier tous les champs des administrés qui doivent être affichés dans cette section dans la page admin.

    """
    list_display = default_list_display(Calcul)


class DecisionAdmin(admin.ModelAdmin):
    """Cette classe est dédiée à la section des décisions dans la page d'admin du projet."""

    list_display = default_list_display(Decision)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.list_display_links = None

    def has_add_permission(self, request):
        return False


class NotationAdmin(admin.ModelAdmin):
    """Cette classe est dédiée à la section notation dans la page d'admin du projet.
     list_display va spécifier tous les champs de notation qui doivent être affichés dans cette section dans la page admin.

    """
    list_display = default_list_display(Notation)


class PosteAdmin(admin.ModelAdmin):
    """Cette classe est dédiée à la section des postes dans la page d'admin du projet.
     list_display va spécifier tous les champs des postes qui doivent être affichés dans cette section dans la page admin.

    """
    list_display = default_list_display(Poste)

class ZoneGeographiqueAdmin(admin.ModelAdmin):
    """Cette classe est dédiée à la section des postes dans la page d'admin du projet.
     list_display va spécifier tous les champs des postes qui doivent être affichés dans cette section dans la page admin.

    """
    list_display = default_list_display(ZoneGeographique)


class PreferencesListeAdmin(admin.ModelAdmin):
    """Cette classe est dédiée à la section de preferences liste dans la page d'admin du projet.
     list_display va spécifier tous les champs de preferences liste qui doivent être affichés dans cette section dans la page admin
    """
    list_display = default_list_display(PreferencesListe)


class FMOBAdmin(admin.ModelAdmin):
    """Cette classe est dédiée à la section de FMOB dans la page d'admin du projet.
     list_display va spécifier tous les champs de FMOB qui doivent être affichés dans cette section dans la page admin.

    """
    list_display = default_list_display(FMOB)


class MarqueAdmin(admin.ModelAdmin):
    """Cette classe est dédiée à la section de Marque dans la page d'admin du projet.
     list_display va spécifier tous les champs de la talbe Marque qui doivent être affichés dans cette section dans la page admin.

    """
    list_display = default_list_display(Marque)


class FiliereAdmin(admin.ModelAdmin):
    """Cette classe est dédiée à la section de Filiere dans la page d'admin du projet.
     list_display va spécifier les champs f_code et domaine de la talbe Filiere qui doivent être affichés dans cette section dans la page admin.

    """
    list_display = default_list_display(Filiere)


class SousVivierAdmin(admin.ModelAdmin):
    """Cette classe est dédiée à la section de sous vivier dans la page d'admin du projet.
     list_display va spécifier les champs sv_id, gestionnaire et sv_libelle de la talbe sous vivier qui doivent être affichés dans cette section dans la page admin.

    """
    list_display = default_list_display(SousVivier)


class RefGestAdmin(admin.ModelAdmin):
    """Cette classe est dédiée à la section de référentiels gestionnaires dans la page d'admin du projet.
     list_display va spécifier les champs de la talbe référentiel gestionnaire qui doivent être affichés dans cette section dans la page admin.

    """
    list_display = default_list_display(RefGest)


class RefOrgAdmin(admin.ModelAdmin):
    """Cette classe est dédiée à la section de référentiels organiques dans la page d'admin du projet.
     list_display va spécifier les champs de la talbe referentiel organique qui doivent être affichés dans cette section dans la page admin.

    """
    list_display = default_list_display(RefOrg)


class RefSvFilAdmin(admin.ModelAdmin):
    """Cette classe est dédiée à la section de référentiels sous-vivier filiere dans la page d'admin du projet.
     list_display va spécifier les champs de la talbe referentiel sous-vivier filiere qui doivent être affichés dans cette section dans la page admin.

    """
    list_display = default_list_display(RefSvFil)


class FichiersExporteAdmin(admin.ModelAdmin):
    """Cette classe est dédiée à la section des fichiers exportés dans la page d'admin du projet.
     list_display va spécifier les champs id, nom_fichier et date_export de la talbe des fichiers exportés qui doivent être affichés dans cette section dans la page admin.

    """
    list_display = default_list_display(FichiersExporte)


# class SousVivierAssociationAdmin(admin.ModelAdmin):
#     """Cette classe est dédiée à la section de SousVivierAssociation dans la page d'admin du projet.
#      list_display va spécifier tous les champs de la talbe SousVivierAssociation qui doivent être affichés dans cette section dans la page admin.

#     """
#     list_display = default_list_display(SousVivierAssociation)


class MarquesGroupeAdmin(admin.ModelAdmin):
    """Cette classe est dédiée à la section de MarquesGroupe dans la page d'admin du projet.
     list_display va spécifier tous les champs de la talbe MarquesGroupe qui doivent être affichés dans cette section dans la page admin.

    """
    list_display = default_list_display(MarquesGroupe)


class CustomUserCreationForm(UserCreationForm):
    """Cette classe est dédiée à la section de creation d'un utilisateur dans la page d'admin du projet.

    """
    class Meta(UserCreationForm.Meta):
        model = CustomUser
        fields = UserCreationForm.Meta.fields + ('id', 'grade')


class CustomUserChangeForm(UserChangeForm):
    """Cette classe est dédiée à la section de changement d'un utilisateur dans la page d'admin du projet.

    """

    class Meta(UserChangeForm.Meta):
        model = CustomUser
        fields = UserCreationForm.Meta.fields + ('id', 'grade')


class CustomUserAdmin(BaseUserAdmin):
    """Cette classe est dédiée à la section des utilisateurs dans la page d'admin du projet.
    list_display va spécifier tous les champs de la talbe CustomUser qui doivent être affichés dans cette section dans la page admin.

    """
    model = CustomUser
    form = CustomUserChangeForm
    add_form = CustomUserCreationForm
    list_display = BaseUserAdmin.list_display + ('id', 'grade')
    fieldsets = BaseUserAdmin.fieldsets + (
        ('Gestionnaire', {
            'fields': ('id', 'grade'),
        }),
    )
    add_fieldsets = BaseUserAdmin.add_fieldsets + (
        ('Gestionnaire', {
            'fields': ('id', 'grade'),
        }),
    )
    # list_display = [field.name for field in CustomUser._meta.get_fields() if not isinstance(field, ManyToManyRel)
    # and not field.name in ['logentry', 'sousvivier']]


class CompetenceAdmin(admin.ModelAdmin):
    """Cette classe est dédiée à la section des competences dans la page d'admin du projet.
    list_display va spécifier tous les champs de la talbe Competence qui doivent être affichés dans cette section dans la page admin.

    """
    list_display = default_list_display(Competence)


class FormationEmploiAdmin(admin.ModelAdmin):
    """Cette classe est dédiée à la section Formation Emploi dans la page d'admin du projet.
    list_display va spécifier tous les champs de la talbe FE qui doivent être affichés dans cette section dans la page admin.

    """
    list_display = ['fe_code', 'fe_libelle', 'fe_garnison_lieu', 'fe_code_postal', 'groupe_fe', 'fe_taux_armement_cible_mdr',
                    'fe_taux_armement_cible_off', 'fe_taux_armement_cible_soff', 'get_mere', 'zone_defense']
    list_filter = ('groupe_fe__groupe_fe_nom', 'fe_garnison_lieu')
    actions = ['modification_taux_armement_mdr', 'modification_taux_armement_off', 'modification_taux_armement_soff', 'attribution_groupe']
    search_fields = ['fe_code']

    @admin.display(description='FE mère')
    def get_mere(self, obj):
        return obj.mere.pk if obj.mere else None

    # Fonctions d'actions supplémentaires
    @admin.action(description="Changer le taux d'armement pour la catégorie MDR")
    def modification_taux_armement_mdr(self, request, queryset):
        """Fonction dédiée à la modification du taux d'armement mdr dans la section Formation Emploi de la page d'administration.

        """
        if 'apply' in request.POST:
            taux = int(request.POST['taux_armement_cible'])
            for fe_id in queryset.values_list('fe_code'):
                fe = FormationEmploi.objects.get(fe_code=fe_id[0])
                fe.fe_taux_armement_cible_mdr = taux
                new_nb_reevalue_mdr = np.ceil(0.01 * taux * fe.fe_nb_poste_reo_mdr)
                new_nb_vacant_mdr = new_nb_reevalue_mdr - fe.fe_nb_poste_occupe_mdr
                fe.fe_nb_poste_reevalue_mdr = new_nb_reevalue_mdr
                fe.fe_nb_poste_vacant_mdr = new_nb_vacant_mdr
                fe.save(update_fields=['fe_taux_armement_cible_mdr', 'fe_nb_poste_reevalue_mdr', 'fe_nb_poste_vacant_mdr'])
            messages.success(request, '{0} FEs ont été mises à jour'.format(queryset.count()))

            return HttpResponseRedirect(request.get_full_path())

        form = TauxArmementForm(initial={'_selected_action': queryset.values_list('fe_code', flat=True)})

        return render(request,
                      'admin/taux_cible_mdr.html',
                      {'form': form, 'formations_emplois': queryset, 'do_action': 'modification_taux_armement_mdr', 'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME})

    modification_taux_armement_mdr.short_description = "Modification du taux d'armement cible pour la categorie MDR"

    @admin.action(description="Changer le taux d'armement pour la catégorie OFF")
    def modification_taux_armement_off(self, request, queryset):
        """Fonction dédiée à la modification du taux d'armement off dans la section Formation Emploi de la page d'administration.

        """
        if 'apply' in request.POST:
            taux = int(request.POST['taux_armement_cible'])
            for fe_id in queryset.values_list('fe_code'):
                fe = FormationEmploi.objects.get(fe_code=fe_id[0])
                fe.fe_taux_armement_cible_off = taux
                new_nb_reevalue_off = np.ceil(0.01 * taux * fe.fe_nb_poste_reo_off)
                new_nb_vacant_off = new_nb_reevalue_off - fe.fe_nb_poste_occupe_off
                fe.fe_nb_poste_reevalue_off = new_nb_reevalue_off
                fe.fe_nb_poste_vacant_off = new_nb_vacant_off
                fe.save(update_fields=['fe_taux_armement_cible_off', 'fe_nb_poste_reevalue_off', 'fe_nb_poste_vacant_off'])
            messages.success(request, '{0} FEs ont été mises à jour'.format(queryset.count()))

            return HttpResponseRedirect(request.get_full_path())

        form = TauxArmementForm(initial={'_selected_action': queryset.values_list('fe_code', flat=True)})

        return render(request,
                      'admin/taux_cible_off.html',
                      {'form': form, 'formations_emplois': queryset, 'do_action': 'modification_taux_armement_off', 'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME})

    modification_taux_armement_off.short_description = "Modification du taux d'armement cible pour la categorie OFF"

    @admin.action(description="Changer le taux d'armement pour la catégorie SOFF")
    def modification_taux_armement_soff(self, request, queryset):
        """Fonction dédiée à la modification du taux d'armement soff dans la section Formation Emploi de la page d'administration.

        """
        if 'apply' in request.POST:
            taux = int(request.POST['taux_armement_cible'])
            for fe_id in queryset.values_list('fe_code'):
                fe = FormationEmploi.objects.get(fe_code=fe_id[0])
                fe.fe_taux_armement_cible_soff = taux
                new_nb_reevalue_soff = np.ceil(0.01 * taux * fe.fe_nb_poste_reo_soff)
                new_nb_vacant_soff = new_nb_reevalue_soff - fe.fe_nb_poste_occupe_soff
                fe.fe_nb_poste_reevalue_soff = new_nb_reevalue_soff
                fe.fe_nb_poste_vacant_soff = new_nb_vacant_soff
                fe.save(update_fields=['fe_taux_armement_cible_soff', 'fe_nb_poste_reevalue_soff', 'fe_nb_poste_vacant_soff'])
            messages.success(request, '{0} FEs ont été mises à jour'.format(queryset.count()))

            return HttpResponseRedirect(request.get_full_path())

        form = TauxArmementForm(initial={'_selected_action': queryset.values_list('fe_code', flat=True)})

        return render(request,
                      'admin/taux_cible_soff.html',
                      {'form': form, 'formations_emplois': queryset, 'do_action': 'modification_taux_armement_soff', 'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME})

    modification_taux_armement_soff.short_description = "Modification du taux d'armement cible pour la categorie SOFF"

    @admin.action(description='Attribuer les FE à un groupe')
    def attribution_groupe(modeladmin, request, queryset):
        """Fonction dédiée à l'attribution du group pour la formation emploi dans la section Formation Emploi de la page d'administration.

        """
        if 'apply' in request.POST:
            nom = request.POST['nom_groupe_fe']
            try:
                groupe_fe = GroupeFe.objects.get(groupe_fe_nom=nom)
            except:
                groupe_fe = GroupeFe(groupe_fe_nom=nom)
                groupe_fe.save()

            fe = FormationEmploi.objects.filter(fe_code__in=queryset.values_list('fe_code'))
            fe.update(groupe_fe_id=groupe_fe.pk)
            messages.success(request, '{0} FEs ont été mises à jour'.format(queryset.count()))

            return HttpResponseRedirect(request.get_full_path())

        form = GroupeFeForm(initial={'_selected_action': queryset.values_list('fe_code', flat=True)})

        return render(request,
                      'admin/groupe_fe.html',
                      {'form': form, 'formations_emplois': queryset, 'do_action': 'attribution_groupe', 'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME})

    attribution_groupe.short_description = "Attribution des FE à un groupe"



# class PcpFeGroupeAdmin(admin.ModelAdmin):
#     """Cette classe est dédiée à l'association des groupes de FE aux gestionnaires PCP dans la page d'admin du projet.

#     """
#     list_display = default_list_display(PcpFeGroupe)
#     form = PcpFeGroupeForm


# Register your models here.

admin.site.register(Administre, AdministreAdmin)
admin.site.register(Calcul, CalculAdmin)
admin.site.register(Decision, DecisionAdmin)
admin.site.register(FichiersExporte, FichiersExporteAdmin)
admin.site.register(Poste, PosteAdmin)
admin.site.register(SousVivier, SousVivierAdmin)
admin.site.register(RefGest, RefGestAdmin)
admin.site.register(RefOrg, RefOrgAdmin)
admin.site.register(RefSvFil, RefSvFilAdmin)
admin.site.register(Notation, NotationAdmin)
admin.site.register(Filiere, FiliereAdmin)
admin.site.register(FormationEmploi, FormationEmploiAdmin)
# admin.site.register(SousVivierAssociation, SousVivierAssociationAdmin)
admin.site.register(FMOB, FMOBAdmin)
admin.site.register(Marque, MarqueAdmin)
admin.site.register(MarquesGroupe, MarquesGroupeAdmin)
admin.site.register(CustomUser, CustomUserAdmin)
admin.site.register(Competence, CompetenceAdmin)
# admin.site.register(PcpFeGroupe, PcpFeGroupeAdmin)
admin.site.register(ZoneGeographique, ZoneGeographiqueAdmin)
