"""This module holds authentication tests for apiv2."""

from django.core.urlresolvers import reverse
from django.db import transaction
from django.test import override_settings
from django.utils.timezone import now, timedelta

from oauth2_provider.models import Application, AccessToken
from rest_framework import permissions, status, viewsets
from rest_framework.test import APIClient

from mtp.apps.api.tests.test_cases import MTPAPITestCase
from mtp.apps.brainstormers.api.serializers import BrainstormerSerializer
from mtp.apps.brainstormers.models import Brainstormer


@override_settings(
    ROOT_URLCONF='mtp.apps.accounts.apiv2.tests.urls.test_authentication_exempt_csrf'
)
class TokenAuthenticationExemptCSRFTestCase(MTPAPITestCase):
    """Check the token authentication mechanism with forced csrf checks.
    The token authentication should allow us to run post method without provide csrf token.

    """

    class TestViewSet(viewsets.ModelViewSet):
        """A simple ViewSet to test post request."""

        queryset = Brainstormer.objects.non_deleted()
        serializer_class = BrainstormerSerializer
        permission_classes = (permissions.IsAuthenticated,)

    @classmethod
    def setUpTestData(cls):
        """We create a access token."""

        super().setUpTestData()

        cls.application = Application.objects.create(
            name="Test Application",
            user=cls.trainer,
            client_type=Application.CLIENT_CONFIDENTIAL,
            authorization_grant_type=Application.GRANT_AUTHORIZATION_CODE,
        )
        cls.access_token = AccessToken.objects.create(
            user=cls.trainer,
            token='123456',
            application=cls.application,
            expires=now() + timedelta(days=365),
        )

    @classmethod
    def setUpClass(cls):
        """Create the api client with forced csrf checks and an url which accept post request."""

        super().setUpClass()

        cls.client_with_csrf = APIClient(enforce_csrf_checks=True)
        cls.url = reverse('brainstormer-list')

    def run_post_request(self, token=None):
        """Run a post request on ``TestViewSet`` with forced csrf checks."""

        data = {
            'name': 'new_fake_brainstormer',
            'session': self.training_session.id,
        }

        if token:
            self.client_with_csrf.credentials(HTTP_AUTHORIZATION='Bearer ' + token)

        return self.client_with_csrf.post(self.url, data, format='json')

    def test_post_request_should_works_without_csrf_token(self):
        """Test that we could run a post method without csrf token through api."""

        # We encapsulate the unauthorized request because it rollback the database
        with transaction.atomic():
            response = self.run_post_request()
            self.assertEqual(response.status_code, status.HTTP_401_UNAUTHORIZED)

        response = self.run_post_request(token=self.access_token.token)
        self.assertEqual(response.status_code, status.HTTP_201_CREATED)
