""" All API views that are used to retrieve data from the database. They
can be categorized by the permissions they require. All views require a
user to be authenticated and most are only accessible by one user group """
import logging

from django.conf import settings
from django.db.models import Avg
from rest_framework import generics, mixins, viewsets, status
from rest_framework.decorators import api_view, list_route
from rest_framework.response import Response

from core import models
from core.models import ExamType, StudentInfo, SubmissionType
from core.permissions import IsReviewer, IsStudent, IsTutorOrReviewer
from core.serializers import (ExamSerializer, StudentInfoSerializer,
                              StudentInfoSerializerForListView,
                              SubmissionNoTypeSerializer, SubmissionSerializer,
                              SubmissionTypeSerializer, TutorSerializer)

log = logging.getLogger(__name__)


@api_view()
def get_jwt_expiration_delta(request):
    return Response({'timeDelta': settings.JWT_AUTH['JWT_EXPIRATION_DELTA']})


@api_view()
def get_user_role(request):
    return Response({'role': request.user.role})


class StudentSelfApiView(generics.RetrieveAPIView):
    """ Gets all data that belongs to one student """
    permission_classes = (IsStudent,)
    serializer_class = StudentInfoSerializer

    def get_object(self) -> StudentInfo:
        """ The object in question is the student associated with the requests
        user. Since the permission IsStudent is satisfied the member exists """
        if self.request.user.is_superuser:
            return StudentInfo.objects.last()
        return self.request.user.student


class StudentSelfSubmissionsApiView(generics.ListAPIView):
    permission_classes = (IsStudent, )
    serializer_class = SubmissionSerializer

    def get_queryset(self):
        return self.request.user.student.submissions


class StudentReviewerApiViewSet(viewsets.ReadOnlyModelViewSet):
    """ Gets a list of all students without individual submissions """
    permission_classes = (IsReviewer,)
    queryset = StudentInfo.objects\
        .select_related('user')\
        .select_related('exam')\
        .prefetch_related('submissions')\
        .prefetch_related('submissions__feedback')\
        .prefetch_related('submissions__type')\
        .all()
    serializer_class = StudentInfoSerializerForListView

    def _set_students_active(self, active):
        for student in self.get_queryset():
            user = student.user
            user.is_active = active
            user.save()

    @list_route(methods=['post'])
    def deactivate(self, request):
        self._set_students_active(False)
        return Response(status=status.HTTP_200_OK)

    @list_route(methods=['post'])
    def activate(self, request):
        self._set_students_active(True)
        return Response(status=status.HTTP_200_OK)


class ExamApiViewSet(viewsets.ReadOnlyModelViewSet):
    """ Gets a list of an individual exam by Id if provided """
    permission_classes = (IsReviewer,)
    queryset = ExamType.objects.all()
    serializer_class = ExamSerializer


class TutorApiViewSet(
        mixins.RetrieveModelMixin,
        mixins.CreateModelMixin,
        mixins.DestroyModelMixin,
        mixins.ListModelMixin,
        viewsets.GenericViewSet):
    """ Api endpoint for creating, listing, viewing or deleteing tutors """
    permission_classes = (IsReviewer,)
    queryset = models.UserAccount.objects.filter(role='Tutor')
    serializer_class = TutorSerializer
    lookup_field = 'username'
    lookup_url_kwarg = 'username'


class SubmissionTypeApiView(viewsets.ReadOnlyModelViewSet):
    """ Gets a list or a detail view of a single SubmissionType """
    queryset = SubmissionType.objects.all()
    serializer_class = SubmissionTypeSerializer


class StatisticsEndpoint(viewsets.ViewSet):

    def list(self, request, *args, **kwargs):
        return Response({
            'submissions_per_type':
            models.SubmissionType.objects.first().submissions.count(),

            'submissions_per_student':
            models.SubmissionType.objects.count(),

            'current_mean_score':
            models.Feedback.objects.aggregate(avg=Avg('score')).get('avg', 0),

            'submission_type_progress':
                models.SubmissionType.get_annotated_feedback_count().values(
                    'feedback_count', 'pk', 'percentage', 'name')
        })


class SubmissionViewSet(viewsets.ReadOnlyModelViewSet):
    permission_classes = (IsTutorOrReviewer, )
    serializer_class = SubmissionNoTypeSerializer

    def get_queryset(self):
        if self.request.user.is_reviewer():
            return models.Submission.objects.all()
        else:
            return models.Submission.objects.filter(
                assignments__subscription__owner=self.request.user
            )