"""This module contains the apiV2-related views of the ``evaluations`` app"""

from django.db.models import Prefetch
from django.shortcuts import get_object_or_404
from django.utils.functional import cached_property

from rest_framework import mixins
from rest_framework import viewsets

from mtp.apps.api.permissions import IsAuthenticatedOrValidOAuthToken
from mtp.apps.trainings.apiv2.views_utils import ConditionallyCachedRetrieveTrainingActivityMixin
from mtp.apps.trainings.models import TrainingSession

from ..models import Criterion, Evaluation, Exercise, Rating

from .serializers import EvaluationSerializer, RatingSerializer


class EvaluationRetrieveView(ConditionallyCachedRetrieveTrainingActivityMixin,
                             viewsets.GenericViewSet):
    """API view to retreive a single ``Evaluation`` instance"""

    permission_classes = [IsAuthenticatedOrValidOAuthToken]

    queryset = Evaluation.objects.non_deleted().prefetch_related(
        Prefetch(
            'exercises',
            queryset=Exercise.objects.non_deleted()
        ),
        Prefetch(
            'exercises__criteria',
            queryset=Criterion.objects.non_deleted()
        )
    )
    serializer_class = EvaluationSerializer


class EvaluationRatingView(mixins.CreateModelMixin,
                           mixins.ListModelMixin,
                           viewsets.GenericViewSet):
    """Api view to list and create ``Rating`` instance(s)"""

    permission_classes = [IsAuthenticatedOrValidOAuthToken]
    serializer_class = RatingSerializer

    @cached_property
    def evaluation(self):
        """Get the evaluation from the urls params

        Returns
        -------
        ``Evaluation``

        Raises
        ------
        Http404

        """

        return get_object_or_404(
            Evaluation.objects.non_deleted(),
            id=self.kwargs['evaluation_uuid']
        )

    @cached_property
    def session(self):
        """Get the training session from the urls params

        Returns
        -------
        ``Evaluation``

        Raises
        ------
        Http404

        """

        return get_object_or_404(
            TrainingSession.objects.non_deleted(),
            id=self.kwargs['session_uuid']
        )

    def get_queryset(self):
        """Filter the ratings accordingly to the current user, the evaluation and the session

        Returns
        -------
        RatingQuerySet

        """

        return Rating.objects.filter(
            session=self.session,
            criterion__exercise__evaluation=self.evaluation
        )

    def get_serializer(self, *args, **kwargs):
        """Override the serializer argument when dealing with a list of ``Rating``

        For the parameters, see ``rest_framework.views.APIView``
        """

        if "data" in kwargs:
            data = kwargs["data"]

            if isinstance(data, list):
                kwargs["many"] = True

        return super().get_serializer(*args, **kwargs)

    def get_serializer_context(self):
        """Override the serializer context to add additional values

        For the parameters, see ``rest_framework.views.APIView``
        """

        context = super().get_serializer_context()
        context['session'] = self.session
        context['judge'] = self.request.user

        return context
