"""This module contains the test cases for the middleware classes of the ``api`` app"""

import datetime
import json

from oauth2_provider.models import AccessToken

from django.conf import settings
from django.test import Client
from django.test.utils import override_settings
from django.utils import timezone

from mtp.apps.api.tests.test_cases import MTPOAuthClientTestCaseMixin
from mtp.apps.common.tests.test_cases import MTPTestCase


@override_settings(ROOT_URLCONF='mtp.apps.common.tests.fake_urls')
class NonDeletedOrDeactivatedUserMiddlewareOauthTestCase(MTPOAuthClientTestCaseMixin, MTPTestCase):
    """Test the ``NonDeletedUserMiddleware`` through Oauth"""

    @classmethod
    def setUpTestData(cls):
        """Create our access token and oauth client"""

        super().setUpTestData()

        # create an OAuth token linked to our trainee
        access_token = AccessToken.objects.create(
            user=cls.trainee,
            token='12345678910',
            application=cls.oauth_application,
            expires=timezone.now() + datetime.timedelta(days=1),
            scope='read write',
        )

        # and use it in a Client
        # NB: Authorization or Accept here won't be found by middlewares
        cls.oauth_client = Client(
            HTTP_AUTHORIZATION='Bearer %s' % access_token,
            HTTP_ACCEPT='application/json',
        )

    def setUp(self):
        """Refresh our trainee"""

        super().setUp()

        self.trainee.refresh_from_db()

    def test_deleted_user_should_not_access_protected_view(self):
        """Test that a deleted user can not access protected view"""

        self.trainee.remove()

        response = self.oauth_client.get('/url-with-auth-or-token-permission/')

        self.assertEqual(response.status_code, 403)

        response_content = json.loads(response.content.decode('utf-8'))
        self.assertEqual(response_content['detail'], 'MTP_USER_DEACTIVATED')

    def test_non_deleted_user_access_protected_view(self):
        """Test that a non-deleted user can access protected view"""

        response = self.oauth_client.get('/url-with-auth-or-token-permission/')

        self.assertEqual(response.status_code, 200)

    def test_deactivated_user_should_not_access_protected_view(self):
        """Test that a deactivated user can not access protected view"""

        self.trainee.is_active = False
        self.trainee.save()

        response = self.oauth_client.get('/url-with-auth-or-token-permission/')

        self.assertEqual(response.status_code, 403)

        response_content = json.loads(response.content.decode('utf-8'))
        self.assertEqual(response_content['detail'], 'MTP_USER_DEACTIVATED')

    def test_non_deactivated_user_access_protected_view(self):
        """Test that a non-deactivated user can access protected view"""

        response = self.oauth_client.get('/url-with-auth-or-token-permission/')

        self.assertEqual(response.status_code, 200)


@override_settings(ROOT_URLCONF='mtp.apps.common.tests.fake_urls')
class NonDeletedOrDeactivatedUserMiddlewareClassicAuthTestCase(MTPTestCase):
    """Test the ``NonDeletedUserMiddleware`` through classic auth"""

    def setUp(self):
        """Refresh our trainee"""

        super().setUp()

        self.trainee.refresh_from_db()

    def test_deleted_user_should_not_access_protected_view(self):
        """Test that a deleted user can not access protected view"""

        self.trainee.remove()

        self.login_as_trainee()

        response = self.client.get('/url-with-auth-or-token-permission/')

        # we are redirected to a dummy login view with non implemented get
        self.assertRedirects(response, str(settings.LOGIN_URL), target_status_code=405)

    def test_non_deleted_user_access_protected_view(self):
        """Test that a non-deleted user can access protected view"""

        self.login_as_trainee()

        response = self.client.get('/url-with-auth-or-token-permission/')

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.data, {})

    def test_deactivated_user_should_not_access_protected_view(self):
        """Test that a deactivated user can not access protected view"""

        self.trainee.is_active = False
        self.trainee.save()

        self.login_as_trainee()

        response = self.client.get('/url-with-auth-or-token-permission/')

        # this case is handled by at the login level for the classic auth
        # so the test differs from ``NonDeletedOrDeactivatedUserMiddlewareOauthTestCase``
        self.assertEqual(response.status_code, 401)

    def test_non_deactivated_user_access_protected_view(self):
        """Test that a non-deactivated user can access protected view"""

        self.login_as_trainee()

        response = self.client.get('/url-with-auth-or-token-permission/')

        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.data, {})
