"""This module contains the views utils for the ``trainings`` app"""

from django.db.models import Q

from rest_framework.mixins import RetrieveModelMixin
from rest_framework_extensions.key_constructor.constructors import DefaultObjectKeyConstructor

from mtp.apps.api.decorators import conditional_cache_response

from ..models import Training


class ConditionallyCachedRetrieveTrainingActivityMixin(RetrieveModelMixin):
    """Mixin to use to cache the activities endpoints of a published training

    This mixin will cache the ``TrainingActivity`` api response
    based on the status of the tied ``Training`` instance.

    Examples
    --------
    You can use "as it is" on a View who implement the ``retrieve`` method:
    >>> from rest_framework.generics import RetrieveAPIView
    >>> class CachedView(RetrieveAPIView, ConditionallyCachedRetrieveTrainingActivityMixin):
    >>>     # This view will be cached

    If you need to override the ``retrieve`` method, you will need to re-apply the decorator:
    >>> from rest_framework.generics import RetrieveAPIView
    >>> from mtp.apps.api.decorators import conditional_cache_response
    >>> class CachedView(RetrieveAPIView, ConditionallyCachedRetrieveTrainingActivityMixin):
    >>>     @conditional_cache_response()
    >>>     def retrieve(self, request, *args, **kwargs):
    >>>         # Custom logic on the retrieve method

    """

    def should_be_cached(self):
        """Check the status of the tied ``Training`` instance

        We check if we need to cache this view using the state of the ``Training``
        linked to the activity.

        Returns
        -------
        bool
            True if the ``Training`` is in ``PUBLISHED`` or ``ARCHIVED`` state
            False otherwise.

        """

        training = Training.objects.only('version_state').filter(
            Q(activities__id__in=[self.kwargs['pk']]) |
            Q(training_sessions__activities__id__in=[self.kwargs['pk']])
        ).first()

        if training and training.version_state in Training.VERSION_STATES.EDITABLE:
            return False

        return True

    @conditional_cache_response(key_func=DefaultObjectKeyConstructor())
    def retrieve(self, request, *args, **kwargs):
        """Apply the ``maybe_cache_response`` decorator

        For the parameters, see ``rest_framework.mixins.RetrieveModelMixin.retrieve``

        """

        return super().retrieve(request, *args, **kwargs)
