from decimal import Decimal

from django.contrib.auth import get_user_model
from django.db import IntegrityError
from django.test import TestCase

from core.models import Bid, Shipment, Trip, format_shipment_unique_id

User = get_user_model()


class ShipmentUniqueIdTests(TestCase):
    def setUp(self):
        self.shipper = User.objects.create_user(
            'shipment-uid@test.com',
            email='shipment-uid@test.com',
            password='secret',
        )
        self.transporter = User.objects.create_user(
            'shipment-uid-t@test.com',
            email='shipment-uid-t@test.com',
            password='secret',
        )

    def _create_shipment(self, suffix):
        return Shipment.objects.create(
            shipper=self.shipper,
            pickup_address=f'A-{suffix}',
            delivery_address=f'B-{suffix}',
            cargo_type='General',
            weight='1 ton',
            vehicle_type_required='Flatbed',
            local=True,
            country_to_country=False,
            status=Shipment.Status.ASSIGNED,
        )

    def test_unique_id_assigned_on_shipment_create(self):
        shipment = self._create_shipment('one')
        self.assertEqual(shipment.unique_id, format_shipment_unique_id(1))

    def test_sequential_unique_ids_never_repeat(self):
        shipments = [self._create_shipment(str(i)) for i in range(3)]
        unique_ids = [s.unique_id for s in shipments]
        self.assertEqual(len(unique_ids), len(set(unique_ids)))
        self.assertEqual(unique_ids, [format_shipment_unique_id(n) for n in (1, 2, 3)])

    def test_allocate_skips_used_suffix(self):
        shipment = self._create_shipment('gap')
        shipment.unique_id = format_shipment_unique_id(5)
        shipment.save(update_fields=['unique_id'])
        shipment2 = self._create_shipment('gap2')
        self.assertEqual(shipment.unique_id, format_shipment_unique_id(5))
        self.assertEqual(shipment2.unique_id, format_shipment_unique_id(6))

    def test_manual_duplicate_unique_id_raises(self):
        self._create_shipment('dup')
        with self.assertRaises(IntegrityError):
            Shipment.objects.create(
                shipper=self.shipper,
                pickup_address='A-dup2',
                delivery_address='B-dup2',
                cargo_type='General',
                weight='1 ton',
                vehicle_type_required='Flatbed',
                unique_id=format_shipment_unique_id(1),
                local=True,
                country_to_country=False,
            )

    def test_trip_api_returns_shipment_unique_id(self):
        shipment = self._create_shipment('trip-api')
        bid = Bid.objects.create(
            shipment=shipment,
            transporter=self.transporter,
            amount=Decimal('100.00'),
            status=Bid.Status.ACCEPTED,
        )
        trip = Trip.objects.create(
            shipment=shipment,
            accepted_bid=bid,
            transporter=self.transporter,
        )
        from api.serializers import TripListSerializer

        data = TripListSerializer(trip).data
        self.assertEqual(data['unique_id'], shipment.unique_id)
