from django.test import TestCase
from django.urls import reverse
from rest_framework_simplejwt.tokens import RefreshToken

from users.models import CustomUser


class RefreshContractTests(TestCase):
    """
    THE REFRESH TOKEN MUST SURVIVE BEING USED.

    `src/renderer/src/lib/apiClient.js` in the app repo reads only `access`
    off the refresh response and then calls
    `saveSession({ access: body.access, refresh: getRefreshToken() })` — it
    re-saves the token it already held. Turn on
    SIMPLE_JWT['ROTATE_REFRESH_TOKENS'] and the server's new token is
    discarded, the old one is blacklisted, and every session ends on its first
    refresh: thirty minutes after signing in, silently, on every machine.

    These tests exist so that flipping that setting fails here rather than in
    the field. If the client is ever changed to read `body.refresh ?? old`,
    delete them in the SAME commit as the settings change.
    """

    def setUp(self):
        self.user = CustomUser.objects.create_user('rotate@example.com', 'pw-for-tests-123')
        self.url = reverse('token-refresh')

    def _refresh(self, token):
        return self.client.post(
            self.url,
            data={'refresh': str(token)},
            content_type='application/json',
        )

    def test_refresh_returns_an_access_token(self):
        response = self._refresh(RefreshToken.for_user(self.user))

        self.assertEqual(response.status_code, 200)
        self.assertIn('access', response.json())

    def test_refresh_does_not_rotate(self):
        """No new refresh token comes back, so the client has nothing to miss."""
        response = self._refresh(RefreshToken.for_user(self.user))

        self.assertNotIn('refresh', response.json())

    def test_the_same_refresh_token_works_twice(self):
        """The exact assertion the client's behaviour depends on."""
        token = RefreshToken.for_user(self.user)

        self.assertEqual(self._refresh(token).status_code, 200)
        self.assertEqual(self._refresh(token).status_code, 200)

    def test_a_blacklisted_token_is_rejected(self):
        """Sign-out has to actually end the session."""
        token = RefreshToken.for_user(self.user)
        token.blacklist()

        self.assertEqual(self._refresh(token).status_code, 401)
