"""This module contains the views of the ``cms`` app"""

from random import shuffle
from urllib.parse import urlparse

from django.core.exceptions import ObjectDoesNotExist
from django.conf import settings
from django.db import models
from django.urls import resolve, Resolver404, reverse
from django.utils.translation import get_language
from django.views.generic import DetailView, TemplateView

from django_discover.models import DiscoverItem

from mtp.apps.common.views_utils import LoginRequiredMixin
from mtp.apps.trainings.models import Training, TrainingActivity


class DiscoverItemsQuerySetMixin:
    """View mixin to get the ``DiscoverItem`` for the current version"""

    @staticmethod
    def get_discover_item_queryset():
        """Get the ``DiscoverItem`` for the current language"""

        # Filter for the current version
        discover_item_queryset_for_version = DiscoverItem.objects.filter(
            is_active=True
        )

        # Filter for the current language
        discover_item_queryset = discover_item_queryset_for_version.for_language(
            get_language()
        )

        # If no discover item exists for the current language, fallback to the default language
        if not discover_item_queryset.exists():
            discover_item_queryset = discover_item_queryset_for_version.for_language(
                settings.DEFAULT_NATURAL_LANGUAGE
            )

        return discover_item_queryset


class Index(LoginRequiredMixin, TemplateView, DiscoverItemsQuerySetMixin):
    """Index page for the cms"""

    template_name = 'cms/index.html'

    def get_randomized_discover_items(self):
        """Get the randomized discover items"""

        discover_items_as_list = list(self.get_discover_item_queryset().annotate(
            sort_order=models.Case(
                models.When(tag=DiscoverItem.TAG_CHOICES.IMPORTANT, then=0),
                models.When(tag=DiscoverItem.TAG_CHOICES.NEW, then=1),
                default=2,
                output_field=models.IntegerField()
            )
        ))

        # Firstly, randomize the list
        shuffle(discover_items_as_list)

        # Secondly, order the item per the "sort_order" key
        return sorted(discover_items_as_list, key=lambda x: x.sort_order)

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

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

        """

        return super().get_context_data(
            current_main_section='index',
            discover_items=self.get_randomized_discover_items(),
            **kwargs
        )


class DiscoverItemDetailView(LoginRequiredMixin, DetailView, DiscoverItemsQuerySetMixin):
    """Detail view to display a single ``DiscoverItem``"""

    template_name = 'cms/discover/discover_item_detail.html'

    def get_queryset(self):
        """Filter the ``DiscoverItem`` queryset"""

        return self.get_discover_item_queryset()

    def get_contextual_discover_item_url(self):
        """Get the current discover item link url if applicable

        Some discover item don't have their "link" attributes filled, so we should
        build manually the link if applicable (ie: for the training activity-related items)

        Returns
        -------
        str or None
            The link_url for the discover item,
            or None.

        """

        activity_types = {
            activity_model.__name__.lower(): activity_model
            for activity_model in TrainingActivity.available_activity_models()
        }
        urls_to_match = {
            'cms:index': 'trainings:activities-private-library',
            'trainings:training-detail': 'trainings:training-detail',
            'trainings:activities-private-library': 'trainings:activities-private-library'
        }

        # The current ``DiscoverItem`` is not related to one of the ``TrainingActivity``,
        # return the default context
        if self.object.slug not in activity_types.keys():
            return

        try:
            # Try to match the referer to an url
            match = resolve(urlparse(self.request.META.get('HTTP_REFERER', None))[2])
            resolved_url = '%s:%s' % (match.namespace, match.url_name)

            if 'training_uuid' in match.kwargs:
                training = Training.objects.non_deleted().get(
                    id=match.kwargs['training_uuid']
                )
                create_url = activity_types[self.object.slug].get_training_create_url(
                    training=training
                )
            else:
                create_url = activity_types[self.object.slug].get_create_url()

            # Finally build the full url (we want to redirect the user AND open a modal)
            return '%s?modal-url=%s' % (
                reverse(urls_to_match[resolved_url], kwargs=match.kwargs),
                create_url
            )

        except (Resolver404, KeyError, ObjectDoesNotExist):
            return

    def get_context_data(self, **kwargs):
        """Add the discover item action url link and title to the context if applicable

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

        """

        item_link = self.get_contextual_discover_item_url()

        if not item_link:
            return super().get_context_data(**kwargs)

        return super().get_context_data(
            discover_link_url=item_link,
            **kwargs
        )
