from datetime import date
import base64

from django.contrib.auth import get_user_model
from django.test import TestCase
from rest_framework.test import APIClient

from accounts.models import KYCDocument, ShipperProfile, UserRole

User = get_user_model()

_TINY_PNG = (
    'data:image/png;base64,'
    + base64.b64encode(
        b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01'
        b'\x08\x02\x00\x00\x00\x90wS\xde\x00\x00\x00\x0cIDATx\x9cc\xf8\x0f'
        b'\x00\x00\x01\x01\x00\x05\x18\xd8N\x00\x00\x00\x00IEND\xaeB`\x82'
    ).decode()
)


class ShipperRegisterNationalIdTests(TestCase):
    def setUp(self):
        self.client = APIClient()
        self.url = '/api/shipper/register/'

    def _payload(self, **overrides):
        data = {
            'email': 'shipper@test.com',
            'password': 'secret123',
            'account_type': ShipperProfile.AccountType.INDIVIDUAL,
            'national_id_number': '  NID-001  ',
            'national_id_expiry_date': '2030-12-31',
        }
        data.update(overrides)
        return data

    def test_register_requires_national_id_or_passport(self):
        response = self.client.post(
            self.url,
            {
                'email': 'shipper@test.com',
                'password': 'secret123',
                'account_type': ShipperProfile.AccountType.INDIVIDUAL,
            },
            format='json',
        )
        self.assertEqual(response.status_code, 400)
        self.assertIn('national ID or passport', str(response.json()['error']))

    def test_register_rejects_expiry_dates_without_id_or_passport(self):
        response = self.client.post(
            self.url,
            {
                'email': 'shipper-exp@test.com',
                'password': 'secret123',
                'account_type': ShipperProfile.AccountType.INDIVIDUAL,
                'national_id_expiry_date': '2030-12-31',
                'passport_expiry_date': '2032-01-15',
            },
            format='json',
        )
        self.assertEqual(response.status_code, 400)

    def test_register_succeeds_with_national_id_file_only(self):
        response = self.client.post(
            self.url,
            {
                'email': 'shipper-nid-file@test.com',
                'password': 'secret123',
                'account_type': ShipperProfile.AccountType.INDIVIDUAL,
                'national_id_file': _TINY_PNG,
            },
            format='json',
        )
        self.assertEqual(response.status_code, 201, response.content)
        user = User.objects.get(email='shipper-nid-file@test.com')
        self.assertTrue(
            KYCDocument.objects.filter(
                user=user,
                document_type=KYCDocument.DocumentType.ID,
            ).exists()
        )

    def test_register_succeeds_with_passport_only(self):
        response = self.client.post(
            self.url,
            {
                'email': 'shipper-pp@test.com',
                'password': 'secret123',
                'account_type': ShipperProfile.AccountType.INDIVIDUAL,
                'passport_number': 'AB1234567',
            },
            format='json',
        )
        self.assertEqual(response.status_code, 201, response.content)
        profile = ShipperProfile.objects.get(user__email='shipper-pp@test.com')
        self.assertEqual(profile.national_id_number, '')
        self.assertEqual(profile.passport_number, 'AB1234567')

    def test_register_succeeds_without_passport(self):
        response = self.client.post(self.url, self._payload(), format='json')
        self.assertEqual(response.status_code, 201, response.content)
        profile = ShipperProfile.objects.get(user__email='shipper@test.com')
        self.assertEqual(profile.national_id_number, 'NID-001')
        self.assertEqual(profile.national_id_expiry_date, date(2030, 12, 31))
        self.assertEqual(profile.passport_number, '')
        self.assertIsNone(profile.passport_expiry_date)
        self.assertEqual(profile.business_name, '')
        self.assertEqual(profile.tax_id, '')

    def test_register_persists_optional_business_name_and_tax_id(self):
        response = self.client.post(
            self.url,
            self._payload(
                business_name='  Khan Trading LLC  ',
                tax_id='  TAX-99  ',
            ),
            format='json',
        )
        self.assertEqual(response.status_code, 201, response.content)
        profile = ShipperProfile.objects.get(user__email='shipper@test.com')
        self.assertEqual(profile.business_name, 'Khan Trading LLC')
        self.assertEqual(profile.tax_id, 'TAX-99')

    def test_register_persists_optional_passport(self):
        response = self.client.post(
            self.url,
            self._payload(
                passport_number='  ab1234567  ',
                passport_expiry_date='2032-01-15',
            ),
            format='json',
        )
        self.assertEqual(response.status_code, 201, response.content)
        profile = ShipperProfile.objects.get(user__email='shipper@test.com')
        self.assertEqual(profile.passport_number, 'AB1234567')
        self.assertEqual(profile.passport_expiry_date, date(2032, 1, 15))

    def test_register_accepts_passport_document_without_kyc_api(self):
        response = self.client.post(
            self.url,
            self._payload(
                passport_number='PP-SIGNUP-1',
                passport_expiry_date='2033-05-01',
                passport_file=_TINY_PNG,
            ),
            format='json',
        )
        self.assertEqual(response.status_code, 201, response.content)
        user = User.objects.get(email='shipper@test.com')
        profile = user.shipper_profile
        self.assertEqual(profile.passport_number, 'PP-SIGNUP-1')
        self.assertIsNotNone(profile.kyc_submitted_at)
        doc = KYCDocument.objects.get(
            user=user,
            document_type=KYCDocument.DocumentType.PASSPORT_COPY,
        )
        self.assertEqual(doc.passport_number, 'PP-SIGNUP-1')
        self.assertEqual(doc.expiry_date, date(2033, 5, 1))
        self.assertTrue(doc.file)
        self.assertEqual(doc.review_status, KYCDocument.ReviewStatus.PENDING)

    def test_register_accepts_national_id_file_as_kyc(self):
        response = self.client.post(
            self.url,
            self._payload(
                national_id_number='NID-FILE-1',
                national_id_expiry_date='2031-06-30',
                national_id_file=_TINY_PNG,
            ),
            format='json',
        )
        self.assertEqual(response.status_code, 201, response.content)
        user = User.objects.get(email='shipper@test.com')
        profile = user.shipper_profile
        self.assertIsNotNone(profile.kyc_submitted_at)
        doc = KYCDocument.objects.get(
            user=user,
            document_type=KYCDocument.DocumentType.ID,
        )
        self.assertTrue(doc.file)
        self.assertEqual(doc.expiry_date, date(2031, 6, 30))
        self.assertEqual(doc.review_status, KYCDocument.ReviewStatus.PENDING)

    def test_register_creates_kyc_for_both_national_id_and_passport_files(self):
        response = self.client.post(
            self.url,
            self._payload(
                national_id_file=_TINY_PNG,
                passport_file=_TINY_PNG,
                passport_number='PP-BOTH-1',
            ),
            format='json',
        )
        self.assertEqual(response.status_code, 201, response.content)
        user = User.objects.get(email='shipper@test.com')
        types = set(
            KYCDocument.objects.filter(user=user).values_list('document_type', flat=True)
        )
        self.assertEqual(
            types,
            {KYCDocument.DocumentType.ID, KYCDocument.DocumentType.PASSPORT_COPY},
        )

    def test_register_accepts_passport_file_without_number(self):
        response = self.client.post(
            self.url,
            self._payload(passport_file=_TINY_PNG),
            format='json',
        )
        self.assertEqual(response.status_code, 201, response.content)
        user = User.objects.get(email='shipper@test.com')
        doc = KYCDocument.objects.get(
            user=user,
            document_type=KYCDocument.DocumentType.PASSPORT_COPY,
        )
        self.assertTrue(doc.file)
        self.assertFalse(doc.passport_number)

    def test_register_accepts_passport_expiry_without_number(self):
        response = self.client.post(
            self.url,
            self._payload(passport_expiry_date='2034-01-01'),
            format='json',
        )
        self.assertEqual(response.status_code, 201, response.content)
        profile = ShipperProfile.objects.get(user__email='shipper@test.com')
        self.assertEqual(profile.passport_expiry_date, date(2034, 1, 1))
        self.assertEqual(profile.passport_number, '')

    def test_register_rejects_duplicate_passport_number(self):
        other = User.objects.create_user('other@test.com', email='other@test.com', password='secret')
        UserRole.objects.create(user=other, role=UserRole.Role.SHIPPER)
        KYCDocument.objects.create(
            user=other,
            document_type=KYCDocument.DocumentType.PASSPORT_COPY,
            file='kyc/test/passport.pdf',
            passport_number='DUP999',
        )
        response = self.client.post(
            self.url,
            self._payload(passport_number='dup999'),
            format='json',
        )
        self.assertEqual(response.status_code, 400)
        self.assertIn('passport_number', response.json()['error'])

    def test_profile_returns_national_id_and_passport_fields(self):
        response = self.client.post(
            self.url,
            self._payload(
                passport_number='PP111',
                passport_expiry_date='2031-06-01',
            ),
            format='json',
        )
        self.assertEqual(response.status_code, 201, response.content)
        token = response.json()['data']['token']
        self.client.credentials(HTTP_AUTHORIZATION=f'Bearer {token}')
        profile_response = self.client.get('/api/shipper/profile/')
        self.assertEqual(profile_response.status_code, 200)
        data = profile_response.json()['data']
        self.assertEqual(data['national_id_number'], 'NID-001')
        self.assertEqual(data['national_id_expiry_date'], '2030-12-31')
        self.assertEqual(data['passport_number'], 'PP111')
        self.assertEqual(data['passport_expiry_date'], '2031-06-01')
