"""This module contains the api-related views of the ``roleplays`` app"""

import json

from django.contrib.auth import get_user_model
from django.core.exceptions import ValidationError as DjangoValidationError
from django.db.models import Prefetch
from django.http import Http404

from rest_framework.exceptions import ValidationError
from rest_framework.generics import ListCreateAPIView, RetrieveAPIView
from rest_framework.response import Response

from mtp.apps.trainings.models import TrainingSession

from ..models import Criterion, Rating, Roleplay, Step
from ..serializers import RatingSerializer, RoleplaySerializer


class RoleplayDetail(RetrieveAPIView):
    """View to retrieve a single instance of ``mtp.apps.roleplays.models.Roleplay``"""

    serializer_class = RoleplaySerializer
    queryset = Roleplay.objects.non_deleted().prefetch_related(
        Prefetch(
            'steps',
            queryset=Step.objects.non_deleted()
        ),
        Prefetch(
            'steps__criteria',
            queryset=Criterion.objects.non_deleted()
        )
    )
    lookup_url_kwarg = 'roleplay_uuid'


class RoleplayRatingsList(ListCreateAPIView):
    """View to get or save the roleplay ratings of the given user.

    Exemple
    -------

    If GET request, data will be returned in this format:

    >>> [
    >>>     { # Criterion quantitative
    >>>         'criterion': criterion1_id,
    >>>         'score': 2
    >>>     },
    >>>     { # Criterion qualitative
    >>>         'criterion': criterion2_id,
    >>>         'text': 'This is a text for the sample criterion.'
    >>>     }
    >>> ]

    If POST request, data is expected to be in a "ratings" field,
    json serialized string, in the same format as above.

    """

    serializer_class = RatingSerializer

    def _get_user(self, pk):
        try:
            return get_user_model().objects.get(pk=pk)
        except get_user_model().DoesNotExist:
            raise Http404

    def _get_training_session(self, pk):
        try:
            return TrainingSession.objects.get(pk=pk)
        except TrainingSession.DoesNotExist:
            raise Http404

    def get_queryset(self):
        return Rating.objects.filter(
            training_session__pk=self.kwargs['session_uuid'],
            trainee__pk=self.kwargs['user_uuid'],
            criterion__step__roleplay__pk=self.kwargs['roleplay_uuid']
        )

    #pylint: disable=redefined-builtin,unused-argument,arguments-differ
    def post(self, request, roleplay_uuid, session_uuid, user_uuid, format=None):
        ratings_data = json.loads(request.POST['ratings'])
        serializer = RatingSerializer(data=ratings_data['ratings'], many=True)
        serializer.is_valid(raise_exception=True)

        try:
            serializer.save(
                training_session=self._get_training_session(session_uuid),
                trainee=self._get_user(user_uuid)
            )
        except DjangoValidationError as error:
            raise ValidationError(
                detail=error.message
            )

        return Response(serializer.data)
