import base64

from django.contrib.auth import get_user_model
from django.test import TestCase
from rest_framework.authtoken.models import Token
from rest_framework.test import APIClient

from accounts.models import KYCDocument, TransporterProfile, 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'
        b'\x00\x00\x00\x01\x08\x06\x00\x00\x00\x1f\x15\xc4\x89'
        b'\x00\x00\x00\nIDATx\x9cc\x00\x01\x00\x00\x05\x00\x01\r\n-\xdb'
        b'\x00\x00\x00\x00IEND\xaeB`\x82'
    ).decode()
)


class TransporterDocumentsApiTests(TestCase):
    def setUp(self):
        self.user = User.objects.create_user('docs@test.com', email='docs@test.com', password='secret')
        UserRole.objects.create(user=self.user, role=UserRole.Role.TRANSPORTER, phone='03000000001', language='en')
        TransporterProfile.objects.create(
            user=self.user,
            account_type=TransporterProfile.AccountType.DRIVER,
            local=True,
            country_to_country=False,
        )
        token, _ = Token.objects.get_or_create(user=self.user)
        self.client = APIClient()
        self.client.credentials(HTTP_AUTHORIZATION=f'Bearer {token.key}')
        self.url = '/api/transporter/documents/'

    def test_two_sided_document_requires_front_and_back(self):
        response = self.client.post(
            self.url,
            {'document_type': 'DRIVER_LICENSE', 'file': _TINY_PNG},
            format='json',
        )
        self.assertEqual(response.status_code, 400)
        self.assertIn('file_back', response.json()['error'])

    def test_insurance_document_type_rejected(self):
        response = self.client.post(
            self.url,
            {'document_type': 'INSURANCE', 'file': _TINY_PNG},
            format='json',
        )
        self.assertEqual(response.status_code, 400)

    def test_fleet_owner_doc_type_rejected_for_individual_driver(self):
        response = self.client.post(
            self.url,
            {'document_type': 'COMPANY_LICENSE', 'file': _TINY_PNG},
            format='json',
        )
        self.assertEqual(response.status_code, 400)
        self.assertIn('document_type', response.json()['error'])

    def test_vehicle_registration_rejected_for_individual_driver_kyc(self):
        response = self.client.post(
            self.url,
            {
                'document_type': 'VEHICLE_REGISTRATION',
                'file': _TINY_PNG,
                'file_back': _TINY_PNG,
            },
            format='json',
        )
        self.assertEqual(response.status_code, 400)
        self.assertIn('document_type', response.json()['error'])

    def test_optional_noc_upload_for_individual_driver(self):
        response = self.client.post(
            self.url,
            {'document_type': 'NOC', 'file': _TINY_PNG},
            format='json',
        )
        self.assertEqual(response.status_code, 201, response.content)
        self.assertEqual(response.json()['data']['document_type'], 'NOC')

    def test_upload_and_upsert_two_sided_document(self):
        create = self.client.post(
            self.url,
            {
                'document_type': 'DRIVER_LICENSE',
                'file': _TINY_PNG,
                'file_back': _TINY_PNG,
            },
            format='json',
        )
        self.assertEqual(create.status_code, 201)
        data = create.json()['data']
        self.assertEqual(data['document_type'], 'DRIVER_LICENSE')
        self.assertTrue(data['file_url'])
        self.assertTrue(data['file_back_url'])
        self.assertEqual(KYCDocument.objects.filter(user=self.user).count(), 1)

        update = self.client.post(
            self.url,
            {'document_type': 'DRIVER_LICENSE', 'file_back': _TINY_PNG},
            format='json',
        )
        self.assertEqual(update.status_code, 201)
        self.assertEqual(KYCDocument.objects.filter(user=self.user).count(), 1)

    def test_update_expiry_date_only(self):
        KYCDocument.objects.create(
            user=self.user,
            document_type=KYCDocument.DocumentType.PASSPORT_COPY,
            file='kyc/test/passport.pdf',
            passport_number='P-EXIST-001',
            expiry_date=None,
        )
        response = self.client.post(
            self.url,
            {'document_type': 'PASSPORT_COPY', 'expiry_date': '2028-06-01'},
            format='json',
        )
        self.assertEqual(response.status_code, 201)
        doc = KYCDocument.objects.get(user=self.user, document_type='PASSPORT_COPY')
        self.assertEqual(str(doc.expiry_date), '2028-06-01')

    def test_single_sided_passport_copy(self):
        response = self.client.post(
            self.url,
            {
                'document_type': 'PASSPORT_COPY',
                'file': _TINY_PNG,
                'passport_number': 'AB1234567',
            },
            format='json',
        )
        self.assertEqual(response.status_code, 201)
        data = response.json()['data']
        self.assertEqual(data['document_type'], 'PASSPORT_COPY')
        self.assertEqual(data['passport_number'], 'AB1234567')
        self.assertTrue(data['file_url'])
        self.assertIsNone(data['file_back_url'])

    def test_passport_number_required(self):
        response = self.client.post(
            self.url,
            {'document_type': 'PASSPORT_COPY', 'file': _TINY_PNG},
            format='json',
        )
        self.assertEqual(response.status_code, 400)
        self.assertIn('passport_number', response.json()['error'])

    def test_passport_number_unique(self):
        other = User.objects.create_user('other-pass@test.com', email='other-pass@test.com', password='secret')
        UserRole.objects.create(user=other, role=UserRole.Role.TRANSPORTER, phone='', language='en')
        TransporterProfile.objects.create(
            user=other,
            account_type=TransporterProfile.AccountType.DRIVER,
            local=True,
            country_to_country=False,
        )
        KYCDocument.objects.create(
            user=other,
            document_type=KYCDocument.DocumentType.PASSPORT_COPY,
            file='kyc/test/other-passport.pdf',
            passport_number='UNIQUE99',
        )
        response = self.client.post(
            self.url,
            {
                'document_type': 'PASSPORT_COPY',
                'file': _TINY_PNG,
                'passport_number': 'unique99',
            },
            format='json',
        )
        self.assertEqual(response.status_code, 400)
        self.assertIn('passport_number', response.json()['error'])

    def test_driver_gcc_requires_country(self):
        response = self.client.post(
            self.url,
            {
                'document_type': 'COUNTRY_GCC',
                'file': _TINY_PNG,
                'file_back': _TINY_PNG,
            },
            format='json',
        )
        self.assertEqual(response.status_code, 400)
        self.assertIn('gcc_country', response.json()['error'])

    def test_driver_gcc_with_country(self):
        response = self.client.post(
            self.url,
            {
                'document_type': 'COUNTRY_GCC',
                'file': _TINY_PNG,
                'file_back': _TINY_PNG,
                'gcc_country': 'AE',
            },
            format='json',
        )
        self.assertEqual(response.status_code, 201)
        data = response.json()['data']
        self.assertEqual(data['gcc_country'], 'AE')
        self.assertEqual(data['gcc_country_name'], 'United Arab Emirates')

    def test_list_returns_transporter_document_types_only(self):
        KYCDocument.objects.create(
            user=self.user,
            document_type=KYCDocument.DocumentType.DRIVER_LICENSE,
        )
        KYCDocument.objects.create(
            user=self.user,
            document_type=KYCDocument.DocumentType.ID,
        )
        response = self.client.get(self.url)
        self.assertEqual(response.status_code, 200)
        types = {item['document_type'] for item in response.json()['data']}
        self.assertEqual(types, {'DRIVER_LICENSE'})


class FleetOwnerDocumentsApiTests(TestCase):
    def setUp(self):
        self.user = User.objects.create_user('fleetdocs@test.com', email='fleetdocs@test.com', password='secret')
        UserRole.objects.create(user=self.user, role=UserRole.Role.TRANSPORTER, phone='03000000002', language='en')
        TransporterProfile.objects.create(
            user=self.user,
            account_type=TransporterProfile.AccountType.FLEET_OWNER,
            local=True,
            country_to_country=False,
            company_name='Fleet Co',
            office_number='+9714000000',
            mobile_number='+9715000000',
            company_location='Dubai Marina',
        )
        token, _ = Token.objects.get_or_create(user=self.user)
        self.client = APIClient()
        self.client.credentials(HTTP_AUTHORIZATION=f'Bearer {token.key}')
        self.url = '/api/transporter/documents/'

    def test_upload_company_license(self):
        response = self.client.post(
            self.url,
            {'document_type': 'COMPANY_LICENSE', 'file': _TINY_PNG},
            format='json',
        )
        self.assertEqual(response.status_code, 201)
        data = response.json()['data']
        self.assertEqual(data['document_type'], 'COMPANY_LICENSE')
        self.assertTrue(data['file_url'])
        self.assertIsNone(data['file_back_url'])

    def test_legacy_company_registration_rejected(self):
        response = self.client.post(
            self.url,
            {'document_type': 'COMPANY_REGISTRATION', 'file': _TINY_PNG},
            format='json',
        )
        self.assertEqual(response.status_code, 400)
        self.assertIn('document_type', response.json()['error'])

    def test_individual_driver_doc_type_rejected_for_fleet_owner(self):
        response = self.client.post(
            self.url,
            {
                'document_type': 'DRIVER_LICENSE',
                'file': _TINY_PNG,
                'file_back': _TINY_PNG,
            },
            format='json',
        )
        self.assertEqual(response.status_code, 400)
        self.assertIn('document_type', response.json()['error'])

    def test_list_returns_fleet_owner_document_types_only(self):
        KYCDocument.objects.create(
            user=self.user,
            document_type=KYCDocument.DocumentType.COMPANY_LICENSE,
            file='kyc/test/license.pdf',
        )
        KYCDocument.objects.create(
            user=self.user,
            document_type=KYCDocument.DocumentType.DRIVER_LICENSE,
            file='kyc/test/license.pdf',
        )
        response = self.client.get(self.url)
        self.assertEqual(response.status_code, 200)
        types = {item['document_type'] for item in response.json()['data']}
        self.assertEqual(types, {'COMPANY_LICENSE'})

    def test_upload_only_three_fleet_owner_types(self):
        for doc_type, extra in (
            ('COMPANY_LICENSE', {}),
            ('PASSPORT_COPY', {'passport_number': 'FO-PASS-001'}),
            ('COUNTRY_GCC', {'file_back': _TINY_PNG, 'gcc_country': 'SA'}),
        ):
            payload = {'document_type': doc_type, 'file': _TINY_PNG, **extra}
            response = self.client.post(self.url, payload, format='json')
            self.assertEqual(response.status_code, 201, msg=doc_type)
            self.assertEqual(response.json()['data']['document_type'], doc_type)
            if doc_type == 'PASSPORT_COPY':
                self.assertEqual(response.json()['data']['passport_number'], 'FO-PASS-001')

    def test_gcc_requires_country_for_fleet_owner(self):
        response = self.client.post(
            self.url,
            {
                'document_type': 'COUNTRY_GCC',
                'file': _TINY_PNG,
                'file_back': _TINY_PNG,
            },
            format='json',
        )
        self.assertEqual(response.status_code, 400)
        self.assertIn('gcc_country', response.json()['error'])

    def test_gcc_rejects_non_gulf_country(self):
        response = self.client.post(
            self.url,
            {
                'document_type': 'COUNTRY_GCC',
                'file': _TINY_PNG,
                'file_back': _TINY_PNG,
                'gcc_country': 'PK',
            },
            format='json',
        )
        self.assertEqual(response.status_code, 400)
        self.assertIn('gcc_country', response.json()['error'])

    def test_profile_includes_company_contact_fields(self):
        response = self.client.get('/api/transporter/profile/')
        self.assertEqual(response.status_code, 200)
        data = response.json()['data']
        self.assertEqual(data['office_number'], '+9714000000')
        self.assertEqual(data['mobile_number'], '+9715000000')
        self.assertEqual(data['company_location'], 'Dubai Marina')

    def test_gcc_countries_endpoint(self):
        response = self.client.get('/api/transporter/gcc-countries/')
        self.assertEqual(response.status_code, 200)
        codes = {item['code'] for item in response.json()['data']}
        self.assertEqual(codes, {'AE', 'SA', 'OM', 'QA', 'BH', 'KW'})
