"""This module holds the ``TrainingActivity`` related views for the ``trainings`` app."""

from django.http import HttpResponseRedirect
from django.shortcuts import get_object_or_404
from django.utils.functional import cached_property
from django.utils.translation import ugettext_lazy as _
from django.views import generic

from mtp.apps.common.views_utils import (
    OrderableListMixin,
    SuccessMessageMixin,
    SyncableDeleteView,
)
from mtp.apps.documents.models import Document
from mtp.apps.evaluations.models import Evaluation
from mtp.apps.ideas.models.ideas import IdeasActivity
from mtp.apps.qrcodes.views import (
    ObjectQRCodeDownloadDetailView,
    ObjectQRCodeDownloadListView,
    QRCodeDownloadMixin,
)
from mtp.apps.roleplays.models import Roleplay
from mtp.apps.trainings.qrcodes import ActivityQRCode
from mtp.apps.workshops.models import Workshop

from ..models import TrainingActivity

from . import TrainingBaseView


class TrainingActivityBase(TrainingBaseView):
    """Base view to manage the training activity

    Define the queryset to use, depending on the user and set the
    ``current_sub_section``in the context.

    """

    pk_url_kwarg = 'activity_uuid'
    model = TrainingActivity

    @cached_property
    def training(self):
        """Try to get the current selected training from the url.

        Raises
        ------
        ``django.http.Http404``
            If the training doesn't exists.

        Returns
        -------
        ``Training`` instance

        """

        return get_object_or_404(
            super().get_training_queryset_for_current_user(),
            pk=self.kwargs['training_uuid']
        )

    def get_queryset(self):
        """Filter the activities for the current ``Training`` instance."""

        return TrainingActivity.objects.non_deleted().for_training(
            self.training
        ).order_by(
            'sort_order'
        )

    def get_context_data(self, **kwargs):
        """Add the ``current_sub_section`` and the current ``Training`` to the context.

        For the parameters, see ``django.forms.generic.base.ContextMixin``
        """

        return super().get_context_data(
            current_sub_section='activities',
            training=self.training,
            **kwargs
        )

    def get_success_url(self):
        """Get the url where to go back when an action is done on a activity.

        It actually returns the url of the activity list.

        """

        return self.training.get_activity_list_url()


class TrainingActivityListView(OrderableListMixin, TrainingActivityBase, generic.ListView):
    """View to list and sort the ``Activity`` instances"""

    template_name = 'cms/trainings/trainingactivity_list.html'

    def get_context_data(self, **kwargs):
        """Add the ``ideas_model_types`` to the context

        For the parameters, see ``django.views.generic.context.ContextMixin``

        """

        return super().get_context_data(
            ideas_model_types=[
                kls.__name__.lower()
                for kls in IdeasActivity.__subclasses__()
            ],
            **kwargs
        )

    def get_queryset(self):
        """Exclude the non-available ``TrainingActivity``"""

        return super().get_queryset().available()


class TrainingActivityEditBase(TrainingActivityBase, SuccessMessageMixin):
    """Base view for the edition of the ``Activity`` instances."""

    def get_queryset(self):
        """Filter the activity that can be edited.

        The activity can be edited only if they belong to a ``DRAFT`` training.

        Returns
        -------
        instance of mtp.apps.trainings.managers.TrainingActivityQuerySet
            The list of activities which can be edited

        """
        return super().get_queryset().editable()


class TrainingActivityDeleteView(TrainingActivityEditBase, SyncableDeleteView):
    """View to soft delete a ``TrainingActivity."""

    template_name = 'cms/trainings/trainingactivity_delete.html'
    success_message = _('Your activity was successfully deleted.')


class TrainingActivityDuplicateView(TrainingActivityEditBase, generic.UpdateView):
    """View to create a duplicate of a given ``Activity`` instance, with confirmation."""

    fields = []
    template_name = 'cms/trainings/trainingactivity_duplicate.html'
    success_message = _('Your activity was successfully duplicated.')

    def post(self, request, *args, **kwargs):
        """Duplicate the activity, and redirect the user.

        For the parameters, see ``django.views.generic.View``

        Returns
        -------
        instance of django.http.HttpResponseRedirect
            A redirect to the url of the list of activities.

        """

        activity = self.get_object()
        activity.duplicate()

        self.send_message()

        return HttpResponseRedirect(self.get_success_url())


# pylint: disable=abstract-method
class ActivityQRCodeDownloadMixin(QRCodeDownloadMixin, TrainingActivityBase):
    """Mixin containing specific methods and attributes to download activity launch QRCode."""

    qrcode_class = ActivityQRCode


class ActivityQRCodeDownloadDetailView(ActivityQRCodeDownloadMixin, ObjectQRCodeDownloadDetailView):
    """View to download QrCode able to launch an activity."""


class ActivityQRCodeDownloadListView(ActivityQRCodeDownloadMixin, ObjectQRCodeDownloadListView):
    """View to download training QrCodes able to launch an activity."""

    def get_queryset(self):
        """Get training activities.

        Only Document, Evaluation, Workshop, Roleplay.
        We can't launch Template with a QRCode like BrainstormerTemplate.

        """
        return super().get_queryset().instance_of(
            Document, Evaluation, Workshop, Roleplay
        )

    def get_filename(self):
        """Get the filename used to name the generated zip file."""
        return str(self.training)
