import io
from decimal import Decimal
from unittest.mock import patch

from django.contrib.auth import get_user_model
from django.core.files.uploadedfile import SimpleUploadedFile
from django.test import TestCase
from rest_framework.authtoken.models import Token
from rest_framework.test import APIClient

from accounts.models import TransporterDriverLink, TransporterProfile, UserRole
from core.models import Bid, ProofOfDelivery, PODPhoto, Shipment, Trip

User = get_user_model()


def _dummy_image(name='test.jpg'):
    return SimpleUploadedFile(
        name,
        b'\xff\xd8\xff\xe0\x00\x10JFIF\x00\x01\x01\x01\x00`\x00`\x00\x00\xff\xdb\x00C\x00\x08\x06\x06\x07\x06\x05\x08\x07\x07\x07\t\t\x08\n\x0c\x14\r\x0c\x0b\x0b\x0c\x19\x12\x13\x0f\x14\x1d\x1a\x1f\x1e\x1d\x1a\x1c\x1c $.\' ",#\x1c\x1c(7),01444\x1f\'9=82<.342\xff\xc0\x00\x0b\x08\x00\x01\x00\x01\x01\x01\x11\x00\xff\xc4\x00\x1f\x00\x00\x01\x05\x01\x01\x01\x01\x01\x01\x00\x00\x00\x00\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\xff\xda\x00\x08\x01\x01\x00\x00?\x00\xbf\x00\xff\xd9',
        content_type='image/jpeg',
    )


class DriverSubmitPODTests(TestCase):
    def setUp(self):
        self.shipper = User.objects.create_user(
            'pod-shipper@test.com', email='pod-shipper@test.com', password='secret',
        )
        UserRole.objects.create(user=self.shipper, role=UserRole.Role.SHIPPER, phone='', language='en')

        self.driver = User.objects.create_user(
            'pod-driver@test.com', email='pod-driver@test.com', password='secret',
        )
        UserRole.objects.create(user=self.driver, role=UserRole.Role.TRANSPORTER, phone='', language='en')
        TransporterProfile.objects.create(
            user=self.driver,
            account_type=TransporterProfile.AccountType.DRIVER,
            local=True,
            country_to_country=False,
            documents_verified=True,
        )

        self.shipment = Shipment.objects.create(
            shipper=self.shipper,
            pickup_address='Pickup A',
            delivery_address='Delivery B',
            cargo_type='General',
            weight='1 ton',
            vehicle_type_required='Flatbed',
            local=True,
            country_to_country=False,
            status=Shipment.Status.ASSIGNED,
        )
        self.bid = Bid.objects.create(
            shipment=self.shipment,
            transporter=self.driver,
            amount=Decimal('500.00'),
            status=Bid.Status.ACCEPTED,
        )
        self.trip = Trip.objects.create(
            shipment=self.shipment,
            accepted_bid=self.bid,
            transporter=self.driver,
            status=Trip.Status.IN_TRANSIT,
        )

        token, _ = Token.objects.get_or_create(user=self.driver)
        self.client = APIClient()
        self.client.credentials(HTTP_AUTHORIZATION=f'Bearer {token.key}')

    @patch('api.views.notify_users')
    def test_submit_pod_with_multiple_photos(self, mock_notify):
        response = self.client.post(
            f'/api/transporter/trips/{self.trip.id}/pod/',
            {
                'receiver_name': 'Ali Khan',
                'receiver_signature': _dummy_image('sig.jpg'),
                'photos': [_dummy_image('p1.jpg'), _dummy_image('p2.jpg'), _dummy_image('p3.jpg')],
            },
            format='multipart',
        )
        self.assertEqual(response.status_code, 201)
        data = response.json()['data']
        self.assertEqual(data['receiver_name'], 'Ali Khan')
        self.assertIsNotNone(data['signature_url'])
        self.assertEqual(len(data['photos']), 3)

        self.trip.refresh_from_db()
        self.assertEqual(self.trip.status, Trip.Status.DELIVERED)
        self.shipment.refresh_from_db()
        self.assertEqual(self.shipment.status, Shipment.Status.DELIVERED)

    @patch('api.views.notify_users')
    def test_submit_pod_with_flexible_photo_field_names(self, mock_notify):
        """Allows uploading multiple POD files under various key names like pods, delivery_photos, etc."""
        response = self.client.post(
            f'/api/transporter/trips/{self.trip.id}/pod/',
            {
                'receiver_name': 'Fatima',
                'pod_photos': [_dummy_image('pod1.jpg'), _dummy_image('pod2.jpg')],
                'delivery_photo': _dummy_image('pod3.jpg'),
            },
            format='multipart',
        )
        self.assertEqual(response.status_code, 201)
        data = response.json()['data']
        self.assertEqual(data['receiver_name'], 'Fatima')
        self.assertEqual(len(data['photos']), 3)

    @patch('api.views.notify_users')
    def test_upload_additional_pods_to_existing_trip_pod(self, mock_notify):
        """Driver can upload additional PODs to an existing delivered trip without duplicate error."""
        # First submission
        res1 = self.client.post(
            f'/api/transporter/trips/{self.trip.id}/pod/',
            {
                'receiver_name': 'Initial Receiver',
                'photos': [_dummy_image('first.jpg')],
            },
            format='multipart',
        )
        self.assertEqual(res1.status_code, 201)
        self.assertEqual(len(res1.json()['data']['photos']), 1)

        # Second submission uploading more PODs
        res2 = self.client.post(
            f'/api/transporter/trips/{self.trip.id}/pod/',
            {
                'photos': [_dummy_image('second.jpg'), _dummy_image('third.jpg')],
            },
            format='multipart',
        )
        self.assertEqual(res2.status_code, 200)
        data = res2.json()['data']
        self.assertEqual(data['receiver_name'], 'Initial Receiver')
        self.assertEqual(len(data['photos']), 3)

    def test_get_pod_endpoint_for_transporter(self):
        """Driver can fetch POD and all its photos via GET."""
        pod = ProofOfDelivery.objects.create(
            trip=self.trip,
            receiver_name='John Doe',
            delivered_at=self.trip.created_at,
        )
        PODPhoto.objects.create(pod=pod, image=_dummy_image('p1.jpg'))
        PODPhoto.objects.create(pod=pod, image=_dummy_image('p2.jpg'))

        response = self.client.get(f'/api/transporter/trips/{self.trip.id}/pod/')
        self.assertEqual(response.status_code, 200)
        data = response.json()['data']
        self.assertEqual(data['receiver_name'], 'John Doe')
        self.assertEqual(len(data['photos']), 2)

    def test_shipper_load_apis_return_full_pod_urls(self):
        """Shipper shipments and trip endpoints return pod details with full absolute URLs."""
        pod = ProofOfDelivery.objects.create(
            trip=self.trip,
            receiver_name='Receiver Jane',
            delivered_at=self.trip.created_at,
        )
        PODPhoto.objects.create(pod=pod, image=_dummy_image('doc1.jpg'))
        PODPhoto.objects.create(pod=pod, image=_dummy_image('doc2.jpg'))

        token, _ = Token.objects.get_or_create(user=self.shipper)
        shipper_client = APIClient()
        shipper_client.credentials(HTTP_AUTHORIZATION=f'Bearer {token.key}')

        # 1. GET /api/shipper/shipments/ — list only published (unassigned) loads
        res_list = shipper_client.get('/api/shipper/shipments/')
        self.assertEqual(res_list.status_code, 200)
        self.assertEqual(res_list.json()['data'], [])

        # 2. GET /api/shipper/shipments/{id}/
        res_detail = shipper_client.get(f'/api/shipper/shipments/{self.shipment.id}/')
        self.assertEqual(res_detail.status_code, 200)
        detail_data = res_detail.json()['data']
        self.assertEqual(detail_data['pod']['receiver_name'], 'Receiver Jane')
        self.assertTrue(detail_data['pod_url'].startswith('http'))
        self.assertEqual(len(detail_data['pod_urls']), 2)

        # 3. GET /api/shipper/trips/
        res_trips = shipper_client.get('/api/shipper/trips/')
        self.assertEqual(res_trips.status_code, 200)
        trip_item = res_trips.json()['data'][0]
        self.assertIsNotNone(trip_item['pod'])
        self.assertTrue(trip_item['pod_url'].startswith('http'))
        self.assertEqual(len(trip_item['pod_urls']), 2)

        # 4. GET /api/shipper/trips/{id}/
        res_trip_detail = shipper_client.get(f'/api/shipper/trips/{self.trip.id}/')
        self.assertEqual(res_trip_detail.status_code, 200)
        trip_detail_data = res_trip_detail.json()['data']
        self.assertIsNotNone(trip_detail_data['pod'])
        self.assertTrue(trip_detail_data['pod_url'].startswith('http'))
        self.assertEqual(len(trip_detail_data['pod_urls']), 2)
        # Nested shipment also has pod_url
        self.assertTrue(trip_detail_data['shipment']['pod_url'].startswith('http'))

        # 5. GET /api/shipper/shipments/history/
        self.shipment.status = Shipment.Status.DELIVERED
        self.shipment.save()
        res_hist = shipper_client.get('/api/shipper/shipments/history/')
        self.assertEqual(res_hist.status_code, 200)
        hist_item = res_hist.json()['data'][0]
        self.assertTrue(hist_item['pod_url'].startswith('http'))
        self.assertEqual(len(hist_item['pod_urls']), 2)

