import logging

from django.core.exceptions import ObjectDoesNotExist
from rest_framework import mixins, status, viewsets
from rest_framework.response import Response

from core import models, permissions, serializers
from core.models import TutorSubmissionAssignment
from core.permissions import IsTutorOrReviewer
from core.serializers import AssignmentDetailSerializer, AssignmentSerializer

log = logging.getLogger(__name__)


class SubscriptionApiViewSet(
        mixins.RetrieveModelMixin,
        mixins.CreateModelMixin,
        mixins.DestroyModelMixin,
        mixins.ListModelMixin,
        viewsets.GenericViewSet):
    permission_classes = (permissions.IsTutorOrReviewer,)
    serializer_class = serializers.SubscriptionSerializer

    def get_queryset(self):
        return models.SubmissionSubscription.objects.filter(
            owner=self.request.user)

    def _get_subscription_if_type_exists(self, data):
        try:
            return models.SubmissionSubscription.objects.get(
                owner=self.request.user,
                query_type=data.get('query_type', ''),
                query_key=data.get('query_key'),
                feedback_stage=data.get(
                    'feedback_stage',
                    models.SubmissionSubscription.FEEDBACK_CREATION)
            )
        except ObjectDoesNotExist:
            return None

    def create(self, request, *args, **kwargs):
        subscription = self._get_subscription_if_type_exists(request.data)
        if subscription and not subscription.deactivated:
            return Response({'Error': 'Subscriptions have to be unique.'},
                            status.HTTP_409_CONFLICT)
        elif subscription and subscription.deactivated:
            serializer = self.get_serializer(subscription,
                                             data=request.data)
        else:
            serializer = self.get_serializer(data=request.data)

        serializer.is_valid(raise_exception=True)
        subscription = serializer.save()

        if subscription.query_type == models.SubmissionSubscription.STUDENT_QUERY:  # noqa
            subscription.reserve_all_assignments_for_a_student()

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


class AssignmentApiViewSet(
        mixins.RetrieveModelMixin,
        mixins.ListModelMixin,
        viewsets.GenericViewSet):
    permission_classes = (IsTutorOrReviewer,)
    queryset = TutorSubmissionAssignment.objects.all()
    serializer_class = AssignmentSerializer

    def _fetch_assignment(self, serializer):
        try:
            serializer.save()
        except models.SubscriptionEnded as err:
            return Response({'Error': str(err)},
                            status=status.HTTP_410_GONE)
        except models.SubscriptionTemporarilyEnded as err:
            return Response({'Error': str(err)},
                            status=status.HTTP_404_NOT_FOUND)
        except models.NotMoreThanTwoOpenAssignmentsAllowed as err:
            return Response({'Error': str(err)},
                            status=status.HTTP_403_FORBIDDEN)
        return Response(serializer.data, status=status.HTTP_201_CREATED)

    def get_queryset(self):
        """ Get only assignments of that user """
        return TutorSubmissionAssignment.objects.filter(
            subscription__owner=self.request.user)

    def destroy(self, request, pk=None):
        """ Stop working on the assignment before it is finished """
        instance = self.get_object()

        if instance.is_done:
            return Response(status=status.HTTP_403_FORBIDDEN)

        instance.delete()
        return Response(status=status.HTTP_204_NO_CONTENT)

    def create(self, request, *args, **kwargs):
        context = self.get_serializer_context()
        serializer = AssignmentDetailSerializer(data=request.data,
                                                context=context)
        serializer.is_valid(raise_exception=True)
        return self._fetch_assignment(serializer)

    def retrieve(self, request, *args, **kwargs):
        assignment = self.get_object()
        serializer = AssignmentDetailSerializer(assignment)
        return Response(serializer.data)