import codecs
import csv
import pandas as pd
from django.http import HttpResponse
from django.shortcuts import render, redirect, get_object_or_404
from django.views.generic import TemplateView
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from django.utils.datastructures import MultiValueDictKeyError

from BasicData.custom_fonctions import get_next_or_prev
from BasicData.models import Annee, Enseignant, Ecue, EnseignantUe, Etudiant, EtudiantUe, Evaluation, MoyenneEcue, Note, \
    ParcoursSemestreUe, Session, TypeEvaluation, Deliberation, Csv,DeliberationUe
from BasicData.templatetags.custom_tag import get_ecue_etudiant_session, get_etudiant_moyenne_ue_session_1, \
    get_etudiant_session_2_moy_ue, get_etudiant_moyenne_ue3, get_etudiant_by_ue_list
from BasicData.templatetags.custom_tag_obj import get_ecue_etudiant, get_etudiant_list
from .forms import *
from django.contrib import messages
import csv
from django.contrib.auth import update_session_auth_hash
from django.contrib.auth.forms import PasswordChangeForm
# Create your views here.
from django.http import JsonResponse
from django.template.loader import render_to_string


# @login_required(login_url="EspaceEnseignant:login", redirect_field_name="EspaceEnseignant:Home")
class HomeView(TemplateView):
    template_name = "EspaceEnseignant/home_content.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        enseignantUes = []
        parcoursSemestreUes = ParcoursSemestreUe.objects.filter(annee=Annee.objects.last())
        for parcoursSemestreUe in parcoursSemestreUes:
            for ecue in parcoursSemestreUe.ue.ecues.all():
                enseignantUe = EnseignantUe.objects.filter(enseignant=self.request.user, ecue=ecue,
                                                           annee=Annee.objects.last()).first()
                if enseignantUe:
                    enseignantUes.append(enseignantUe)

        context['enseignantUes'] = enseignantUes
        context['parcoursSemestreUes'] = parcoursSemestreUes.first()
        return context


class EnseignantProfile(TemplateView):
    template_name = "EspaceEnseignant/profile.html"


def ImportNoteView(request, ecueId):
    context = {}
    context['typeEvaluations'] = TypeEvaluation.objects.all()
    context['sessions'] = Session.objects.all()
    context['notes'] = Note.objects.none()
    if request.method == "POST":
        fichier = request.FILES['fichier']
        reader = csv.DictReader(codecs.iterdecode(fichier, encoding="utf-8"))
        typeEvaluation_id = request.POST['typeEvaluationId']
        session_id = request.POST['sessionId']
        evaluation = request.POST['evaluation']
        evaluation = Evaluation.objects.create(libelle=evaluation, typeEvaluation_id=typeEvaluation_id,
                                               session_id=session_id, ecue_id=ecueId, annee=Annee.objects.last())
        notes = []

        for row in reader:
            try:
                etudiant = Etudiant.objects.get(nce=row['nce'])
                value = float(row['notes']) if row['notes'] else None
                if value:
                    note = Note.objects.create(etudiant=etudiant, evaluation=evaluation, note=value)
                    notes.append(note)
            except Etudiant.DoesNotExist:
                messages.error(request, f"Le NCE : {row['nce']} n'appartient a aucun etudiant !")
                evaluation.delete()
                return render(request, 'EspaceEnseignant/import.html', context=context)
            except MultiValueDictKeyError:
                messages.error(request, "Vous devez renseigner les champs nce et notes pour faire l'importation !")
                evaluation.delete()
                return render(request, 'EspaceEnseignant/import.html', context=context)

        context['notes'] = notes

    context['ecueId'] = ecueId

    return render(request, 'EspaceEnseignant/import.html', context=context)


def ExportNoteView(request, ecueId, sessionId, delib=False):
    ecue = Ecue.objects.get(pk=ecueId)
    ue = ecue.ue
    annee = Annee.objects.last()
    parcourSemestreUe = ParcoursSemestreUe.objects.filter(ue=ue, annee=annee).first()
    etudiantUes = EtudiantUe.objects.filter(parcoursSemestreUe=parcourSemestreUe)
    evaluations = Evaluation.objects.filter(ecue_id=ecueId, session_id=sessionId, annee=Annee.objects.last())
    session = Session.objects.get(id=sessionId)
    file_name = f"notes_{ecue.libelle}_{session.libelle}_{annee.libelle}.csv"
    response = HttpResponse(
        content_type='text/csv',
        headers={'Content-Disposition': f"attachment; filename={file_name}"},
    )
    writer = csv.writer(response)

    header = ['NCE', 'NOM', 'PRENOMS']
    for evaluation in evaluations:
        header.append(evaluation.libelle)

    if delib:
        header += ['Moyenne reelle', 'moyenne repechee']
    else:
        header.append('Moyenne')

    writer.writerow(header)

    for etudiantUe in etudiantUes:
        row = [etudiantUe.etudiant.nce, etudiantUe.etudiant.nom, etudiantUe.etudiant.prenoms]
        moy = None
        for evaluation in evaluations:
            note = None
            try:
                note = Note.objects.get(etudiant=etudiantUe.etudiant, evaluation=evaluation)
            except Note.DoesNotExist:
                pass

            row.append(note.note if note else None)

        try:
            moy = MoyenneEcue.objects.get(moyenneUe__etudiant=etudiantUe.etudiant, ecue=ecue)
        except MoyenneEcue.DoesNotExist:
            pass

        if moy:
            row.append(moy.note)
            if delib and moy.note_repechee:
                row.append(moy.note_repechee)

        writer.writerow(row)

    return response


class AddNoteView(TemplateView):
    template_name = 'EspaceEnseignant/ajouter_note.html'

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['ue'] = Ecue.objects.get(id=context['ecueId']).ue
        return context
        
#===========================================

@login_required(login_url='BasicData:login')
def enseignant_home(request):
    # ROLE
    user = Enseignant.objects.get(email=request.user.email)

    # On recupere l'enseignant
    enseignant = Enseignant.objects.get(email=request.user.email)
    # O recupere les UE de l'Enseignant
    EnseignantUes = EnseignantUe.objects.filter(enseignant=enseignant)

    annee_univ = Annee.objects.last()
    UEs =[]
    for enst in EnseignantUes:
        #print(enst.ecue.ue.libelle)
        try:
            UEs = Ue.objects.get(id=enst.ecue.ue.id)
        except Ue.DoesNotExist:
            UEs = None
    # On recupere la deliberation
    if UEs:
        try:
            delib = DeliberationUe.objects.get(ue=UEs,annee=annee_univ,session=Session.objects.get(id=1))
        except DeliberationUe.DoesNotExist:
            delib =None
    else:
        delib = None

    # =================== DELIBERATION UE =================
    form2 = DeliberationsUeForm()
    if request.method == 'POST':
        if 'deliberationue' in request.POST:
            form2 = DeliberationsUeForm(request.POST)
            if form2.is_valid():
                cd = form2.cleaned_data
                session = cd.get('session')
                note = cd.get('note')

                #ON CREE LA DELIBERATION
                DeliberationUe.objects.create(
                    annee=annee_univ,
                    ue=UEs,
                    session=session,
                    note=note,
                    user = Enseignant.objects.get(email=request.user)
                )
                form2 = DeliberationsUeForm()
                messages.success(request, "La délibération UE (" + UEs.code + ") réussie")
            else:
                messages.error(request, 'Veuillez verifier les champs svp!')
    else:
        form2 = DeliberationsUeForm()


    context={
        'user': user,
        'enseignant':enseignant,
        'EnseignantUes':EnseignantUes,
        'Ue':UEs,
        'form2':form2,
        #'formEc':formEc,
        'delib':delib
    }
    return render(request,'EspaceEnseignant/home_content.html',context)


# Nouvelle vue pour Ajout de note
@login_required(login_url='BasicData:login')
def add_note_views(request, id,an):
    # ROLE
    user = enseign = Enseignant.objects.get(email=request.user.email)
    annee = Annee.objects.get(id=an)

    # On recupere les infos UE de l'Ecue
    ue = Ecue.objects.get(id=id).ue
    ecue = Ecue.objects.get(id=id)

    # PARAMETRE POUR LE FILTRE
    args = [annee.id,ue.ufr.id,ue.niveau.id,ecue.id]

    # ON ORDONNE LA LISTE
    etudiantUes = get_etudiant_by_ue_list([annee,ue])

    #print(get_etudiant_by_ue_list([annee,ue]))


    session_ini = session = Session.objects.get(id=1)

    SFForm = AnneeFilterForm(request.POST)
    if request.method == 'POST':
        if 'sessionFilter' in request.POST:
            SFForm = AnneeFilterForm(request.POST)
            if SFForm.is_valid():
                cd = SFForm.cleaned_data
                SF = int(cd.get('libelle'))

                if SF == 1:
                    etudiantUes = get_etudiant_by_ue_list([annee,ue])
                else:
                    etudiantUes = get_ecue_etudiant_session(args)

                session_ini = session = Session.objects.get(id=SF)


    # ON recupere la derniere Année
    annee_univ = Annee.objects.last()

    # On recupere les types d'évaluation et les Sessions
    TypeEvaluations = TypeEvaluation.objects.all()
    Sessions = Session.objects.all()

    # On recupere toute les Evaluation de l'Ecue
    Evaluation_enseignant = Evaluation.objects.filter(ecue=ecue, annee=annee,session=session_ini)
    EvalAnZip = list(zip(Evaluation_enseignant,[annee for EV in Evaluation_enseignant],[session_ini for EV in Evaluation_enseignant]))


    # ON RECUPERE LA DELIBERATION DE L'ECUE
    # On initialise la session a 1
    try:
        delib_ecue = Deliberation.objects.filter(annee=annee, ecue=ecue, session=session_ini).last()
    except Deliberation.DoesNotExist:
        delib_ecue = None

    tpEv = TypeEvaluation.objects.all()
    sess = Session.objects.all().order_by('libelle')

    form3 = CsvModelForm(request.POST or None, request.FILES or None)
    if 'importer' in request.POST:
        if form3.is_valid():
            form3.save()
            cd = form3.cleaned_data
            session_post = cd.get('session')
            typeEvaluation = cd.get('typeEvaluation')
            libelle = cd.get('libelle')
            anUniv = cd.get('annee')

            # On recupere la session, le type d'évaluation
            #session_obj = Session.objects.get(id=session)
            session_obj = Session.objects.get(id=session_post)
            typeEvaluation_obj = TypeEvaluation.objects.get(id=typeEvaluation)
            # si c'est un CC on enregistre pas la session
            if typeEvaluation_obj.id == 2: # Controle Continu
                sess = session_obj
            else:
                sess = session_obj

            #ON CREE L'EVALUATION
            new_Evaluation = Evaluation.objects.create(
                libelle = libelle,
                typeEvaluation = typeEvaluation_obj,
                ecue = ecue,
                session = sess,
                #annee = annee,
                annee = Annee.objects.get(id=anUniv),
                enseignant = enseign
            )

            form3 = CsvModelForm()
            obj = Csv.objects.get(activated=False)
            obj.activated = True
            obj.save()

            datas = pd.read_csv(obj.file_name.path, delimiter=';')
            datas.dropna(how="all", inplace=True)
            note_obj = None
            for i, data in datas.iterrows():
                etudiant = Etudiant.objects.filter(nce=data['NCE']).last()
                # On recupere l'objet etudiant
                if etudiant:
                    note_obj = Note.objects.create(
                        note=data['NOTE'],
                        etudiant=etudiant,
                        evaluation=new_Evaluation,
                        annee=Annee.objects.get(id=anUniv),
                        ecue=ecue
                    )
            if note_obj:
                messages.success(request, 'Importation de note réussie')
                form3 = CsvModelForm()
                return redirect('/enseignant/add_note_views/' + str(id) + '/' + str(an) + '/')
            else:
                messages.error(request, "Echec d'importation de note ")
                return redirect('/enseignant/add_note_views/' + str(id) + '/' + str(an) + '/')

    # ADD EVALUATION
    form = AddEvalForm(request.POST)
    if 'addevalBtn' in request.POST:
        if form.is_valid():
            cd = form.cleaned_data
            session_post = cd.get('session')
            typeEvaluation = cd.get('typeEvaluation')
            libelle = cd.get('libelle')
            anUniv = cd.get('annee')

            # On recupere la session, le type d'évaluation
            # session_obj = Session.objects.get(id=session)
            session_obj = Session.objects.get(id=session_post)
            typeEvaluation_obj = TypeEvaluation.objects.get(id=typeEvaluation)
            # si c'est un CC on enregistre pas la session
            if typeEvaluation_obj.id == 2:  # Controle Continu
                sess = session_obj
            else:
                sess = session_obj

            # ON CREE L'EVALUATION
            new_Evaluation = Evaluation.objects.create(
                libelle=libelle,
                typeEvaluation=typeEvaluation_obj,
                ecue=ecue,
                session=sess,
                # annee = annee,
                annee=Annee.objects.get(id=anUniv),
                enseignant=enseign
            )
            messages.success(request,"L'évaluation a été créée avec succès")
            return redirect('/enseignant/add_note_views/'+str(id)+'/'+str(an)+'/')
        else:
            messages.error(request,"Vérifiez les champs svp")


    # ADD EVALUATION
    form2 = AddNoteForm(request.POST)
    if 'addENBtn' in request.POST:
        if form2.is_valid():
            cd = form2.cleaned_data
            Etnote = cd.get('note')
            evalutn = cd.get('evaluation')
            etudNt = cd.get('etudiant')

            Note.objects.create(
                note=Etnote,
                #etudiant=Etudiant.objects.get(id=etudNt),
                etudiant=etudNt,
                #evaluation=Evaluation.objects.get(id=evalutn),
                evaluation=evalutn,
                # annee = Annee.objects.get(id=anUniv),
                annee=evalutn.annee,
                # annee = annee,
                ecue=ecue
            )
            messages.success(request, "Etudiant noté avec succès")
            return redirect('/enseignant/add_note_views/' + str(id) + '/' + str(an) + '/')
        else:
            messages.error(request,"Vérifiez les champs svp")


    # EDIT NOTE
    form4 = NoteEditForm()
    if 'NoteEditBtn' in request.POST:
        form4 = NoteEditForm(request.POST)
        if form4.is_valid():
            cd = form4.cleaned_data
            nobj = cd.get('obj')
            vals = cd.get('note')

            # ON RECUPERE LA NOTE
            note = Note.objects.get(id=nobj)
            note.note = float(vals)
            note.save()
            messages.success(request, "Note modifiée avec succès")
            return redirect('/enseignant/add_note_views/' + str(id) + '/' + str(an) + '/')
        else:
            messages.error(request, "Vérifiez les champs svp")
            return redirect('/enseignant/add_note_views/' + str(id) + '/' + str(an) + '/')

    # EDIT NOTE
    form5 = ObjIdForm()
    if 'DelEvaBtn' in request.POST:
        form5 = ObjIdForm(request.POST)
        if form5.is_valid():
            cd = form5.cleaned_data
            obId = cd.get('objID')
            evaluation = Evaluation.objects.get(id=obId)
            # print(evaluation)
            evaluation.delete()
            messages.success(request, "Supprimé avec succès")
            return redirect('/enseignant/add_note_views/' + str(id) + '/' + str(an) + '/')
        else:
            messages.error(request, "Vérifiez les champs svp")
            return redirect('/enseignant/add_note_views/' + str(id) + '/' + str(an) + '/')

    # ========================================

    context = {
        'user': user,
        'ue': ue,
        'tpEv': tpEv,
        'sess': sess,
        #'parcourSemestreUe': parcourSemestreUe,
        'etudiantUes': etudiantUes,
        'TypeEvaluations': TypeEvaluations,
        'Sessions': Sessions,
        'SFForm': SFForm,
        'form': form,
        'form2': form2,
        'form4': form4,
        'form5': form5,
        'EvalEns': Evaluation_enseignant,
        'EvalAnZip': EvalAnZip,
        #'notes_n': all_notes,
        'enseign': enseign,
        'enseignant': Enseignant.objects.get(email=request.user.email),
        'id_ecue': id,
        'id_ecue2': [ecue,annee,session_ini],
        'form3':form3,
        'ecue':ecue,
        'delib_ecue':delib_ecue,
        'annee':annee,
        'session_ini':session_ini,
        'annee_univ':annee_univ,
        'annees':Annee.objects.all().order_by('-id'),

    }
    return render(request, 'EspaceEnseignant/ajouter_note_view.html', context)


# ======= ADD NOTE
@login_required(login_url='BasicData:login')
def add_note(request, id, ecue, ev):
    # ROLE
    user = Enseignant.objects.get(email=request.user.email)

    # On recupere les infos UE de l'Ecue
    ue = Ecue.objects.get(id=ecue).ue
    ecu = Ecue.objects.get(id=ecue)
    # On recupere tout les parcourSemestreUe de la derniere année
    parcourSemestreUe = ParcoursSemestreUe.objects.filter(ue=ue, annee=Annee.objects.last()).first()
    # on recupere les etudiants du parcourSemestreUe
    etudiant = Etudiant.objects.get(id=id)
    # On recupere l'annee
    annee = Evaluation.objects.get(id=ev).annee

    # ENREGISTRER NOTE
    form = NoteForm()
    if request.method == 'POST':
        # if 'enregistrer' in request.POST:
        form = NoteForm(request.POST)
        if form.is_valid():
            cd = form.cleaned_data
            note = cd.get('note')
            etudiant = cd.get('etudiant')
            evaluation = cd.get('evaluation')
            # annee = cd.get('annee')
            # typeEvaluation = cd.get('typeEvaluation')

            # On verifie si la note existe deja

            # ON ENREGISTRE LA NOTE
            Note.objects.create(
                note=note,
                etudiant=etudiant,
                evaluation=evaluation,
                annee=annee,
                ecue=ecu
            )
            form = NoteForm()
            messages.success(request, "L'Etudiant (" + etudiant.nce + ") a bien été noté")
            return redirect('/enseignant/add_note_views/' + str(ecue))
        else:
            messages.error(request, 'Veuillez verifier les Champs svp!')
    else:
        form = NoteForm()

    context = {
        'user': user,
        'ue': ue,
        'parcourSemestreUe': parcourSemestreUe,
        'etudiant': etudiant,
        'form': form,
        'ev': ev,
        'ecu': ecu,
    }
    return render(request, 'EspaceEnseignant/add_note.html', context)


@login_required(login_url='BasicData:login')
def manage_password(request):
    # ROLE
    user = Enseignant.objects.get(email=request.user.email)

    show_form = 'show'
    if request.method == 'POST':
        form = PasswordChangeForm(request.user, request.POST)
        if form.is_valid():
            user = form.save()
            cd = form.cleaned_data
            an = cd.get('old_password')
            update_session_auth_hash(request, user)  # Important!
            messages.success(request, 'Votre mot de passe a bien été modifié!')
            show_form ='hide'
        else:
            messages.error(request, 'Verifiez les champs')
    else:
        form = PasswordChangeForm(request.user)
    context = {'user':user,'form':form,'show_form':show_form}
    return render(request,'EspaceEnseignant/change_password.html',context)

class DeliberationView(TemplateView):
    template_name = "EspaceEnseignant/deliberation.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['ecue'] = Ecue.objects.get(id=context['ecueId'])
        return context
