"""
The signed-in waitlist pair.

The thing worth a test: joining takes NO body. A signed-in user must not be
able to put an address they do not own on the list, which is the whole reason
the anonymous path has a code round trip.
"""

from django.contrib.auth import get_user_model
from django.test import TestCase
from rest_framework_simplejwt.tokens import AccessToken

from .models import WaitlistEntry

User = get_user_model()


class SignedInWaitlistTests(TestCase):

    def setUp(self):
        self.user = User.objects.create_user(
            email='member@example.com', password='a-long-enough-passphrase',
        )
        self.auth = {'HTTP_AUTHORIZATION': f'Bearer {AccessToken.for_user(self.user)}'}

    def _status(self):
        return self.client.get('/api/waitlist/status/', **self.auth)

    def _join(self, data=None):
        return self.client.post('/api/waitlist/join/', data or {}, **self.auth)

    def test_status_requires_a_signed_in_user(self):
        self.assertEqual(self.client.get('/api/waitlist/status/').status_code, 401)

    def test_status_before_joining(self):
        body = self._status().json()

        self.assertFalse(body['joined'])
        self.assertIsNone(body['joined_at'])
        self.assertTrue(body['launch_label'])

    def test_joining_uses_the_account_address_and_verifies_it(self):
        response = self._join()

        self.assertEqual(response.status_code, 200)
        self.assertTrue(response.json()['joined'])
        self.assertIsNotNone(response.json()['joined_at'])

        entry = WaitlistEntry.objects.get(email='member@example.com')
        self.assertTrue(entry.verified)
        # No code is minted, because there is nothing left to prove — and a
        # stored code would be a live credential nobody will ever use.
        self.assertEqual(entry.verification_code, '')

    def test_a_body_cannot_name_somebody_elses_address(self):
        self._join({'email': 'victim@example.com'})

        self.assertFalse(WaitlistEntry.objects.filter(email='victim@example.com').exists())
        self.assertTrue(WaitlistEntry.objects.filter(email='member@example.com').exists())

    def test_joining_twice_is_not_an_error_and_keeps_the_first_date(self):
        first = self._join().json()
        second = self._join().json()

        self.assertEqual(first['joined_at'], second['joined_at'])
        self.assertEqual(WaitlistEntry.objects.filter(email='member@example.com').count(), 1)

    def test_an_unverified_row_from_the_anonymous_form_is_adopted(self):
        entry = WaitlistEntry.objects.create(email='member@example.com')
        entry.generate_verification_code()

        self.assertTrue(self._join().json()['joined'])

        entry.refresh_from_db()
        self.assertTrue(entry.verified)
        self.assertEqual(entry.verification_code, '')
