""" This module holds the views of the ``metaplans`` app. """

import csv

from django.core.exceptions import PermissionDenied
from django.core.urlresolvers import reverse
from django.http import HttpResponse
from django.shortcuts import get_object_or_404
from django.utils.functional import cached_property
from django.utils.translation import ugettext as _
from django.views.generic.detail import DetailView
from django.views.generic.edit import CreateView, UpdateView
from django.views.generic.list import ListView

from mtp.apps.accounts.models import MTPUser
from mtp.apps.common.utils import EXCEL_BOM
from mtp.apps.common.views_utils import (
    AjaxResponseMixin,
    ConditionalMixin,
    RestrictToSuperuserOrTrainerMixin,
    SuccessMessageMixin,
    SyncableDeleteView,
)
from mtp.apps.import_export.exceptions import ImportDataError
from mtp.apps.import_export.views import XLSExportDetailView, ActivityXLSImportView
from mtp.apps.trainings.models import Training, TrainingSession

from .forms import MetaplanForm, MetaplanPropositionForm
from .models import Metaplan, MetaplanProposition


class MetaplanSessionListView(RestrictToSuperuserOrTrainerMixin, ListView):
    """ Return Metaplan List for a session. """

    def get_queryset(self):
        session = get_object_or_404(TrainingSession, id=self.kwargs['session_id'])
        return Metaplan.objects.filter(session=session, is_deleted=False)

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        session = get_object_or_404(TrainingSession, id=self.kwargs['session_id'])
        context.update({
            'session': session,
        })
        return context


class MetaplanDetailView(RestrictToSuperuserOrTrainerMixin, DetailView):
    """ Detail of Metaplan propositions. """

    model = Metaplan


class MetaplanEditBaseMixin(RestrictToSuperuserOrTrainerMixin, SuccessMessageMixin):
    """ Edit base for Metaplan. """

    model = Metaplan

    def get_success_url(self):
        return reverse(
            'metaplans:list_by_session', kwargs={'session_id': self.object.session.id})


class MetaplanCreateView(ConditionalMixin, MetaplanEditBaseMixin, CreateView):
    """ Create Metaplan. """

    form_class = MetaplanForm
    success_message = _('Your metaplan was successfully created.')

    @cached_property
    def session(self):
        """Get the session associated with this request"""

        return get_object_or_404(TrainingSession, id=self.kwargs['session_id'])

    def get_success_url(self):
        """Get the url of the redirection when create is successful"""

        return reverse(
            'metaplans:list_by_session', kwargs={'session_id': self.session.id})

    def get_initial(self):
        """Get initial data for the form"""

        initial = {'session': self.session}

        return initial

    def is_condition_met(self):
        """Only allow create when session is not closed"""

        return not self.session.is_closed

    def condition_not_met(self):
        """Action to take if the session is closed.

        Raises
        ------
        PermissionDenied
            When the session is closed.

        """

        raise PermissionDenied


class MetaplanUpdateView(MetaplanEditBaseMixin, UpdateView):
    """ Update Metaplan. """

    form_class = MetaplanForm
    success_message = _('Your metaplan was successfully updated.')


class MetaplanDeleteView(MetaplanEditBaseMixin, SyncableDeleteView):
    """ Delete Metaplan. """

    success_message = _('Your metaplan was successfully deleted.')


class MetaplanPropositionEditBaseMixin(RestrictToSuperuserOrTrainerMixin, SuccessMessageMixin):
    """ Edit base for Metaplan Proposition. """

    model = MetaplanProposition

    def get_success_url(self):
        return reverse(
            'metaplans:detail',
            kwargs={'pk': self.kwargs['metaplan_id']}
        )


class MetaplanPropositionCreateView(MetaplanPropositionEditBaseMixin, CreateView):
    """ Create Metaplan Proposition. """

    form_class = MetaplanPropositionForm
    success_message = _('Your metaplan proposition was successfully created.')

    def get_initial(self):
        metaplan = get_object_or_404(Metaplan, id=self.kwargs['metaplan_id'])
        initial = {'metaplan': metaplan}
        return initial

    def get_form(self, form_class=None):
        form = super(MetaplanPropositionCreateView, self).get_form(form_class)
        metaplan = get_object_or_404(Metaplan, id=self.kwargs['metaplan_id'])

        # Change field queryset for adapt them to context session and metaplan
        session_users_ids = metaplan.session.users.values_list('id', flat=True)
        form.fields['user'].queryset = MTPUser.objects.filter(
            id__in=session_users_ids
        )
        return form


class MetaplanExportView(RestrictToSuperuserOrTrainerMixin, DetailView):
    """ Export Metaplan propositions. """

    model = Metaplan

    def get(self, *args, **kwargs):
        super(MetaplanExportView, self).get(*args, **kwargs)

        # Create the HttpResponse object with the appropriate CSV header.
        response = HttpResponse(content_type='text/csv')
        response['Content-Disposition'] = 'attachment; filename="metaplan.csv"'

        writer = csv.writer(response, delimiter=';')

        # Header
        writer.writerow([EXCEL_BOM])  # BOM for excel
        writer.writerow([
            'Metaplan Propositions',
            self.object.name])
        writer.writerow([])

        # Generation of CSV
        grouped_propositions = self.object.get_grouped_propositions()
        for group, propositions in grouped_propositions.items():
            writer.writerow([
                'Group',
                'n°' + str(group),
                '%s propositions' % (len(propositions))])
            for ind, proposition in enumerate(propositions):
                writer.writerow([str(ind + 1),
                                 proposition.text,
                                 proposition.user])

        return response
