from django.urls import reverse
from rest_framework import status
from rest_framework.test import (APIRequestFactory, APITestCase,
                                 force_authenticate)

from core.views import (ExamApiViewSet, StudentReviewerApiViewSet,
                        StudentSelfApiView, CorrectorApiViewSet)
from util.factories import GradyUserFactory, make_exams


class AccessRightsOfStudentAPIViewTests(APITestCase):
    """ All tests that ensure that only students can see what students
    should see belong here """

    @classmethod
    def setUpTestData(cls):
        cls.factory = APIRequestFactory()
        cls.user_factory = GradyUserFactory()

    def setUp(self):
        self.exam = make_exams(exams=[{
                'module_reference': 'Test Exam 01',
                'total_score': 100,
                'pass_score': 60,
            }])[0]
        self.student = self.user_factory.make_student(exam=self.exam)
        self.tutor = self.user_factory.make_tutor()
        self.reviewer = self.user_factory.make_reviewer()
        self.request = self.factory.get(reverse('student-page'))
        self.view = StudentSelfApiView.as_view()

    def test_unauthenticated_access_denied(self):
        response = self.view(self.request)
        self.assertEqual(status.HTTP_401_UNAUTHORIZED, response.status_code)

    def test_tutor_has_no_access(self):
        force_authenticate(self.request, user=self.tutor)
        response = self.view(self.request)
        self.assertEqual(status.HTTP_403_FORBIDDEN, response.status_code)

    def test_reviewer_has_no_access(self):
        force_authenticate(self.request, user=self.reviewer)
        response = self.view(self.request)
        self.assertEqual(status.HTTP_403_FORBIDDEN, response.status_code)

    def test_student_is_authorized(self):
        force_authenticate(self.request, user=self.student)
        response = self.view(self.request)
        self.assertEqual(status.HTTP_200_OK, response.status_code)


class AccessRightsOfTutorAPIViewTests(APITestCase):
    """ Tests to ensure that only Reviewers have access to the TutorList
        information """
    @classmethod
    def setUpTestData(cls):
        cls.factory = APIRequestFactory()
        cls.user_factory = GradyUserFactory()

    def setUp(self):
        self.exam = make_exams(exams=[{
                'module_reference': 'Test Exam 01',
                'total_score': 100,
                'pass_score': 60,
            }])[0]
        self.student = self.user_factory.make_student(exam=self.exam)
        self.tutor = self.user_factory.make_tutor()
        self.reviewer = self.user_factory.make_reviewer()
        self.request = self.factory.get(reverse('corrector-list'))
        self.view = CorrectorApiViewSet.as_view({'get': 'list'})

    def test_unauthenticated_access_denied(self):
        response = self.view(self.request)
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

    def test_student_has_no_access(self):
        force_authenticate(self.request, user=self.student)
        response = self.view(self.request)
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

    def test_tutor_has_no_access(self):
        force_authenticate(self.request, user=self.tutor)
        response = self.view(self.request)
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

    def test_reviewer_has_access(self):
        force_authenticate(self.request, user=self.reviewer)
        response = self.view(self.request)
        self.assertEqual(response.status_code, status.HTTP_200_OK)


class AccessRightsOfStudentReviewerAPIViewTest(APITestCase):
    """ Tests to ensure that only Reviewers have access to the
    StudentReviewerApi endpoint information"""

    @classmethod
    def setUpTestData(cls):
        cls.factory = APIRequestFactory()
        cls.user_factory = GradyUserFactory()

    def setUp(self):
        self.exam = make_exams(exams=[{
                'module_reference': 'Test Exam 01',
                'total_score': 100,
                'pass_score': 60,
            }])[0]
        self.student = self.user_factory.make_student(exam=self.exam)
        self.tutor = self.user_factory.make_tutor()
        self.reviewer = self.user_factory.make_reviewer()
        self.request = self.factory.get(reverse('student-list'))
        self.view = StudentReviewerApiViewSet.as_view({'get': 'list'})

    def test_unauthenticated_access_denied(self):
        response = self.view(self.request)
        self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

    def test_student_has_no_access(self):
        force_authenticate(self.request, user=self.student)
        response = self.view(self.request)
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

    def test_tutor_has_no_access(self):
        force_authenticate(self.request, user=self.tutor)
        response = self.view(self.request)
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

    def test_reviewer_has_access(self):
        force_authenticate(self.request, user=self.reviewer)
        response = self.view(self.request)
        self.assertEqual(response.status_code, status.HTTP_200_OK)


class AccessRightsOfExamTypeAPIViewTest(APITestCase):
    """ Tests who can access the exam list. The rational here is, that this
    list contains information about what number of points was necessary to pass
    the exam. There is no reason why anyone should see this information except
    for their own module. """

    @classmethod
    def setUpTestData(cls):
        cls.factory = APIRequestFactory()
        cls.user_factory = GradyUserFactory()

    def setUp(self):
        self.exam = make_exams(exams=[{
                'module_reference': 'Test Exam 01',
                'total_score': 100,
                'pass_score': 60,
            }])[0]
        self.student = self.user_factory.make_student(exam=self.exam)
        self.tutor = self.user_factory.make_tutor()
        self.reviewer = self.user_factory.make_reviewer()
        self.request = self.factory.get(reverse('examtype-list'))
        self.view = ExamApiViewSet.as_view({'get': 'list'})

    def test_student_has_no_access(self):
        force_authenticate(self.request, user=self.student)
        response = self.view(self.request)
        self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

    # TODO see issue #90 for details
    # def test_tutor_has_no_access(self):
    #     force_authenticate(self.request, user=self.tutor)
    #     response = self.view(self.request)
    #     self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)

    def test_reviewer_has_access(self):
        force_authenticate(self.request, user=self.reviewer)
        response = self.view(self.request)
        self.assertEqual(response.status_code, status.HTTP_200_OK)