from decimal import Decimal
from unittest.mock import patch

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 ShipperProfile, TransporterProfile, UserRole, Vehicle
from core.load_discovery import (
    shipment_matches_transporter_vehicle_types,
    vehicle_matches_required_type,
)
from core.models import Shipment, Zone

User = get_user_model()


class MultiVehicleTypesApiTests(TestCase):
    def setUp(self):
        self.user = User.objects.create_user(
            'multitype@test.com', email='multitype@test.com', password='secret',
        )
        UserRole.objects.create(user=self.user, role=UserRole.Role.TRANSPORTER, phone='', language='en')
        TransporterProfile.objects.create(
            user=self.user,
            account_type=TransporterProfile.AccountType.DRIVER,
            documents_verified=True,
            local=True,
            country_to_country=False,
            tc_id='mt-1',
        )
        self.token, _ = Token.objects.get_or_create(user=self.user)
        self.client = APIClient()
        self.client.credentials(HTTP_AUTHORIZATION=f'Bearer {self.token.key}')

        self.shipper = User.objects.create_user(
            'mtship@test.com', email='mtship@test.com', password='secret',
        )
        UserRole.objects.create(user=self.shipper, role=UserRole.Role.SHIPPER, phone='', language='en')
        ShipperProfile.objects.create(user=self.shipper, account_type=ShipperProfile.AccountType.INDIVIDUAL)
        Zone.objects.create(country_code='AE', radius_km=Decimal('50'))

    def test_create_with_vehicle_types_array(self):
        response = self.client.post(
            '/api/transporter/vehicles/',
            {
                'vehicle_types': ['Container 40 Feet / 20 Feet', 'Flat Bed 12m'],
                'registration_number': 'MT-001',
                'load_capacity': '5000.00',
            },
            format='json',
        )
        self.assertEqual(response.status_code, 201, response.content)
        data = response.json()['data']
        self.assertEqual(data['vehicle_type'], 'Container 40 Feet / 20 Feet')
        self.assertEqual(
            data['vehicle_types'],
            ['Container 40 Feet / 20 Feet', 'Flat Bed 12m'],
        )
        vehicle = Vehicle.objects.get(pk=data['id'])
        self.assertEqual(vehicle.vehicle_type, 'Container 40 Feet / 20 Feet')
        self.assertEqual(vehicle.vehicle_types, ['Container 40 Feet / 20 Feet', 'Flat Bed 12m'])

    def test_create_with_legacy_vehicle_type_string(self):
        response = self.client.post(
            '/api/transporter/vehicles/',
            {
                'vehicle_type': 'Flat Bed 12m',
                'registration_number': 'MT-002',
                'load_capacity': '5000.00',
            },
            format='json',
        )
        self.assertEqual(response.status_code, 201, response.content)
        data = response.json()['data']
        self.assertEqual(data['vehicle_type'], 'Flat Bed 12m')
        self.assertEqual(data['vehicle_types'], ['Flat Bed 12m'])

    def test_create_requires_type(self):
        response = self.client.post(
            '/api/transporter/vehicles/',
            {
                'registration_number': 'MT-003',
                'load_capacity': '5000.00',
            },
            format='json',
        )
        self.assertEqual(response.status_code, 400)

    def test_vehicle_matches_any_declared_type(self):
        vehicle = Vehicle.objects.create(
            owner=self.user,
            vehicle_type='Container 40 Feet / 20 Feet',
            vehicle_types=['Container 40 Feet / 20 Feet', 'Flat Bed 12m'],
            registration_number='MT-004',
            load_capacity=Decimal('5000'),
            is_verified=True,
            is_active=True,
        )
        self.assertTrue(vehicle_matches_required_type(vehicle, 'Flat Bed 12m'))
        self.assertTrue(vehicle_matches_required_type(vehicle, 'Container 40 Feet / 20 Feet'))
        self.assertFalse(vehicle_matches_required_type(vehicle, 'Box Trailer 15m'))

    @patch('api.views.country_code_for_point', return_value='AE')
    @patch('api.views.get_latest_device_position')
    def test_available_shipments_matches_any_vehicle_type(self, mock_position, _country):
        mock_position.return_value = {'latitude': 24.8610, 'longitude': 67.0020, 'raw': {}}
        Vehicle.objects.create(
            owner=self.user,
            vehicle_type='Container 40 Feet / 20 Feet',
            vehicle_types=['Container 40 Feet / 20 Feet', 'Flat Bed 12m'],
            registration_number='MT-005',
            load_capacity=Decimal('5000'),
            is_verified=True,
            is_active=True,
        )
        flat = Shipment.objects.create(
            shipper=self.shipper,
            pickup_address='A',
            pickup_lat=Decimal('24.8607000'),
            pickup_lon=Decimal('67.0011000'),
            pickup_country_code='AE',
            delivery_address='B',
            delivery_country_code='AE',
            cargo_type='General',
            weight='1 ton',
            vehicle_type_required='Flat Bed 12m',
            suggested_price=Decimal('1000.00'),
            local=True,
            country_to_country=False,
            status=Shipment.Status.PUBLISHED,
        )
        container = Shipment.objects.create(
            shipper=self.shipper,
            pickup_address='C',
            pickup_lat=Decimal('24.8620000'),
            pickup_lon=Decimal('67.0030000'),
            pickup_country_code='AE',
            delivery_address='D',
            delivery_country_code='AE',
            cargo_type='General',
            weight='1 ton',
            vehicle_type_required='Container 40 Feet / 20 Feet',
            suggested_price=Decimal('1200.00'),
            local=True,
            country_to_country=False,
            status=Shipment.Status.PUBLISHED,
        )
        other = Shipment.objects.create(
            shipper=self.shipper,
            pickup_address='E',
            pickup_lat=Decimal('24.8630000'),
            pickup_lon=Decimal('67.0040000'),
            pickup_country_code='AE',
            delivery_address='F',
            delivery_country_code='AE',
            cargo_type='General',
            weight='1 ton',
            vehicle_type_required='Box Trailer 15m',
            suggested_price=Decimal('900.00'),
            local=True,
            country_to_country=False,
            status=Shipment.Status.PUBLISHED,
        )

        vehicles = list(Vehicle.objects.filter(owner=self.user, is_verified=True, is_active=True))
        self.assertTrue(shipment_matches_transporter_vehicle_types(flat, vehicles))
        self.assertTrue(shipment_matches_transporter_vehicle_types(container, vehicles))
        self.assertFalse(shipment_matches_transporter_vehicle_types(other, vehicles))

        response = self.client.get('/api/transporter/available-shipments/?country_code=AE')
        self.assertEqual(response.status_code, 200)
        ids = {row['id'] for row in response.json()['data']['shipments']}
        self.assertIn(flat.id, ids)
        self.assertIn(container.id, ids)
        self.assertNotIn(other.id, ids)
