import logging

from rest_framework import mixins, status, viewsets
from rest_framework.response import Response

from core import models, permissions, serializers

log = logging.getLogger(__name__)


class FeedbackApiView(
        mixins.CreateModelMixin,
        mixins.RetrieveModelMixin,
        viewsets.GenericViewSet):
    """ Gets a list of an individual exam by Id if provided """
    permission_classes = (permissions.IsTutorOrReviewer,)
    queryset = models.Feedback.objects.all()
    serializer_class = serializers.FeedbackSerializer
    lookup_field = 'of_submission__pk'
    lookup_url_kwarg = 'submission_pk'

    def _tutor_attempts_to_change_final_feedback(self, serializer):
        feedback_is_final = serializer.instance.is_final
        user_is_tutor = self.request.user.role == models.UserAccount.TUTOR
        return feedback_is_final and user_is_tutor

    def _get_implicit_assignment_for_user(self, submission):
        return models.TutorSubmissionAssignment.objects.get(
            subscription__owner=self.request.user,
            submission=submission
        )

    def _request_user_does_not_own_assignment(self, serializer):
        try:
            submission = serializer.validated_data['of_submission']
            assignment = self._get_implicit_assignment_for_user(submission)
            return assignment.subscription.owner != self.request.user
        except models.TutorSubmissionAssignment.DoesNotExist as err:
            return True

    def _tutor_attempts_to_set_first_feedback_final(self, serializer):
        is_final_set = serializer.validated_data.get('is_final', False)
        user_is_tutor = self.request.user.role == models.UserAccount.TUTOR
        return is_final_set and user_is_tutor

    def _tutor_is_allowed_to_change_own_feedback(self, serializer):
        submission = self.get_object().of_submission
        assignment = self._get_implicit_assignment_for_user(submission)
        youngest = models.TutorSubmissionAssignment.objects \
            .filter(submission=submission) \
            .order_by('-created') \
            .first()

        return assignment == youngest

    def _tutor_attempts_to_patch_first_feedback_final(self, serializer):
        is_final_set = serializer.validated_data.get('is_final', False)
        submission = self.get_object().of_submission
        assignment = self._get_implicit_assignment_for_user(submission)
        in_creation = assignment.subscription.feedback_stage == models.SubmissionSubscription.FEEDBACK_CREATION  # noqa
        return is_final_set and in_creation

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data=request.data)
        serializer.is_valid(raise_exception=True)

        if self._tutor_attempts_to_set_first_feedback_final(serializer):
            return Response(
                {'For tutors it is not allowed to create feedback final.'},
                status=status.HTTP_403_FORBIDDEN)

        if self._request_user_does_not_own_assignment(serializer):
            return Response(
                {'This user has no permission to create this feedback'},
                status=status.HTTP_403_FORBIDDEN)

        self.perform_create(serializer)
        return Response(serializer.data,
                        status=status.HTTP_201_CREATED)

    def partial_update(self, request, **kwargs):
        feedback = self.get_object()
        serializer = self.get_serializer(feedback, data=request.data,
                                         partial=True)

        serializer.is_valid(raise_exception=True)
        if self._tutor_attempts_to_change_final_feedback(serializer):
            return Response(
                {"Changing final feedback is not allowed"},
                status=status.HTTP_403_FORBIDDEN)

        if self._tutor_attempts_to_patch_first_feedback_final(serializer):
            return Response(
                {'Cannot set the first feedback final unless user reviewer'},
                status=status.HTTP_403_FORBIDDEN)

        if not self._tutor_is_allowed_to_change_own_feedback(serializer):
            return Response(
                {'Sorry, but somebody else is already working on this on'},
                status=status.HTTP_403_FORBIDDEN)

        serializer.save()
        return Response(serializer.data)