

from django.urls import reverse_lazy
from django.forms.models import modelformset_factory
from django.shortcuts import get_object_or_404
from django.shortcuts import redirect, render
from django.views.generic.detail import DetailView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.views.generic.list import ListView

from xSACdb.roles.decorators import require_training_officer
from xSACdb.roles.mixins import RequireTrainingOfficer
from xSACdb.views import ActionView
from xsd_members.bulk_select import get_bulk_members
from xsd_training.forms import *


class SessionCreate(RequireTrainingOfficer, CreateView):
    model = Session
    form_class = SessionCreateForm
    template_name = 'session_create.html'


class SessionPlanner(RequireTrainingOfficer, UpdateView):
    model = Session
    fields = ['name', 'when', 'where', 'notes']
    template_name = 'session_edit.html'

    def pl_formset(self, bare=False):
        SessionPlannerTraineeFormSet = modelformset_factory(
            PerformedLesson, form=SessionPLMapForm,
            extra=0
        )
        if bare == True: return SessionPlannerTraineeFormSet
        formset = SessionPlannerTraineeFormSet(
            queryset=PerformedLesson.objects
                .filter(session=self.object)
        )
        return formset

    def get_context_data(self, **kwargs):
        # Call the base implementation first to get a context
        context = super(SessionPlanner, self).get_context_data(**kwargs)
        # Add our own custom context
        context['performed_lessons_formset'] = self.pl_formset()
        context['traineegroup_select'] = TraineeGroupSelectForm()
        return context

    def get(self, request, *args, **kwargs):
        self.object = self.get_object()
        # FIXME, this has been left as a GET as nested POST forms do not work
        if 'remove-pl' in request.GET:
            self.remove_pl(request.GET['remove-pl'])
        return super(SessionPlanner, self).get(request, *args, **kwargs)

    def remove_pl(self, pk):
        pl = get_object_or_404(PerformedLesson, pk=pk)
        pl.delete()

    def post(self, request, *args, **kwargs):
        self.object = self.get_object()
        pl_formset = self.pl_formset(bare=True)
        if request.POST['form-TOTAL_FORMS'] != 0:
            formset = pl_formset(request.POST)
            if formset.is_valid():
                formset.save()
        return super(SessionPlanner, self).post(request, *args, **kwargs)

    def get_success_url(self):
        return reverse('xsd_training:SessionList') + '?last=' + self.kwargs['pk']


class SessionAction(RequireTrainingOfficer, ActionView):
    model = Session

    def add(self, request):
        members = get_bulk_members(request)
        self.get_object().add_trainees(members)

    def add_tg(self, request):
        tg = get_object_or_404(TraineeGroup, pk=request.POST['traineegroup'])
        self.get_object().add_trainee_group(tg)


class SessionList(RequireTrainingOfficer, ListView):
    model = Session
    template_name = 'session_list.html'
    context_object_name = 'sessions'

    def get_context_data(self, **kwargs):
        context = super(SessionList, self).get_context_data(**kwargs)
        if 'last' in self.request.GET:
            context['last'] = int(self.request.GET['last'])
        else:
            context['last'] = 0
        return context

    def get_queryset(self):
        qs = super(SessionList, self).get_queryset().order_by('when').exclude(completed=True)
        return qs


class SessionComplete(RequireTrainingOfficer, DetailView):
    model = Session
    template_name = 'session_complete.html'
    context_object_name = 'session'

    def build_pls_formset(self, bare=False):
        SessionCompleteFormSet = modelformset_factory(
            PerformedLesson, form=SessionCompleteForm,
            extra=0
        )
        if not bare:
            formset = SessionCompleteFormSet(
                queryset=PerformedLesson.objects
                    .filter(session=self.object)
            )
        else:
            formset = SessionCompleteFormSet
        return formset

    def get_context_data(self, **kwargs):
        # Call the base implementation first to get a context
        context = super(SessionComplete, self).get_context_data(**kwargs)
        # Add our own custom context
        context['performed_lessons_formset'] = self.build_pls_formset()
        return context

    def get_trainees(self, request):
        trainees = []
        for item in request.POST:
            if re.match('trainee', item):
                trainee_pk = item[5:]
                trainees.append(MemberProfile.objects.get(pk=trainee_pk))
        return trainees

    def set_pl(self, id, completed, partially_completed, public_notes, private_notes):
        pl = id
        if not completed and not partially_completed:
            # This will be a no-show, so delete the PL
            pl.delete()
        else:
            if completed and partially_completed:
                completed = False  # Mark as not completed if partially is ticked

            # Stick data in object
            pl.completed = completed
            pl.partially_completed = partially_completed
            pl.public_notes = public_notes
            pl.private_notes = private_notes
            # And save it
            pl.save()

    def set_pl_save(self, id, completed, partially_completed, public_notes, private_notes):
        pl = id
        if completed and partially_completed:
            completed = False  # Mark as not completed if partially is ticked

        # Stick data in object
        pl.completed = completed
        pl.partially_completed = partially_completed
        pl.public_notes = public_notes
        pl.private_notes = private_notes
        # And save it
        pl.save()

    def post(self, request, *args, **kwargs):
        SessionCompleteFormSet = self.build_pls_formset(True)
        formset = SessionCompleteFormSet(request.POST)
        if formset.is_valid():
            if 'complete' in request.POST:
                for form in formset.cleaned_data:
                    self.set_pl(form['id'], form['completed'], form['partially_completed'], form['public_notes'],
                                form['private_notes'])
                this_session = self.get_object()
                this_session.completed = True
                this_session.save()
            else:
                for form in formset.cleaned_data:
                    self.set_pl_save(form['id'], form['completed'], form['partially_completed'], form['public_notes'],
                                     form['private_notes'])
                return self.get(request, *args, **kwargs)
            return redirect(reverse_lazy('xsd_training:SessionList'))
        else:
            return self.get(request, *args, **kwargs)


class SessionDelete(RequireTrainingOfficer, DeleteView):
    model = Session
    template_name = 'session_confirm_delete.html'
    success_url = reverse_lazy('xsd_training:SessionList')

    def get_context_data(self, **kwargs):
        context = super(SessionDelete, self).get_context_data(**kwargs)
        context['pls'] = PerformedLesson.objects.filter(session=self.object)
        return context


@require_training_officer
def pool_sheet(request):
    if request.GET:
        form = PoolSheetOptions(request.GET)
        if form.is_valid():
            return pool_sheet_generate(request, form)
    else:
        form = PoolSheetOptions()

    return render(request, 'pool_sheet.html', {'form': form})


@require_training_officer
def pool_sheet_generate(request, form):
    session = form.cleaned_data['session']
    pls = PerformedLesson.objects.filter(session=session).order_by(
        form.cleaned_data['sort_by'])

    pls_extended = []

    number_of_notes = form.cleaned_data['number_of_notes']
    for pl in pls:
        if pl.lesson:
            # If lesson is specified for PL, get prev feedback
            recent_pls = PerformedLesson.objects.filter(
                trainee=pl.trainee,
                lesson__mode=pl.lesson.mode,
                completed=True
            ).order_by('date')[:number_of_notes]
            notes = []
            for rpl in recent_pls:
                if rpl.public_notes or rpl.private_notes: notes.append(rpl)
            pls_extended.append((pl, notes))
        else:
            # Else don't bother
            pls_extended.append((pl, None))

    return render(request, 'pool_sheet_generate.html', {
        'session': session,
        'pls_extended': pls_extended,
        'show_public_notes': form.cleaned_data['show_public_notes'],
        'show_private_notes': form.cleaned_data['show_private_notes'],
        'comments_column': form.cleaned_data['comments_column'],
        'signature_column': form.cleaned_data['signature_column'],
    })
