from decimal import Decimal

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 TransporterProfile, UserRole
from billing.models import Payment
from core.models import Bid, Shipment, Trip

User = get_user_model()


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

        self.driver = User.objects.create_user(
            'driver-ind-lists@test.com',
            email='driver-ind-lists@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,
        )

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

    def _trip(self, status):
        shipment = Shipment.objects.create(
            shipper=self.shipper,
            pickup_address='A',
            pickup_company='Pickup Co',
            pickup_country_code='AE',
            delivery_address='B',
            dropoff_company='Dropoff Co',
            cargo_type='General',
            weight='1 ton',
            vehicle_type_required='Flatbed',
            local=True,
            country_to_country=False,
            status=Shipment.Status.ASSIGNED,
        )
        bid = Bid.objects.create(
            shipment=shipment,
            transporter=self.driver,
            amount=Decimal('100.00'),
            status=Bid.Status.ACCEPTED,
        )
        return Trip.objects.create(
            shipment=shipment,
            accepted_bid=bid,
            transporter=self.driver,
            status=status,
        )

    def test_assigned_list_only_assigned(self):
        assigned = self._trip(Trip.Status.ASSIGNED)
        self._trip(Trip.Status.EN_ROUTE)
        self._trip(Trip.Status.COMPLETED)

        r = self.client.get('/api/transporter/my-trips/assigned/')
        self.assertEqual(r.status_code, 200)
        ids = [t['id'] for t in r.json()['data']['trips']]
        self.assertEqual(ids, [assigned.id])
        self.assertEqual(r.json()['data']['count'], 1)
        shipment_row = r.json()['data']['trips'][0]['shipment']
        self.assertEqual(shipment_row['pickup_company'], 'Pickup Co')
        self.assertEqual(shipment_row['dropoff_company'], 'Dropoff Co')
        self.assertEqual(shipment_row['currency'], 'AED')
        self.assertEqual(r.json()['data']['trips'][0]['currency'], 'AED')

    def test_completed_list_only_completed(self):
        self._trip(Trip.Status.ASSIGNED)
        self._trip(Trip.Status.DELIVERED)
        completed = self._trip(Trip.Status.COMPLETED)

        r = self.client.get('/api/transporter/my-trips/completed/')
        self.assertEqual(r.status_code, 200)
        ids = [t['id'] for t in r.json()['data']['trips']]
        self.assertEqual(ids, [completed.id])

    def test_completed_list_includes_payment_pending_cod(self):
        trip = self._trip(Trip.Status.COMPLETED)
        Payment.objects.create(
            trip=trip,
            payer=self.shipper,
            payee=self.driver,
            method=Payment.Method.CASH,
            amount='100.00',
            status=Payment.Status.PENDING_COD,
        )

        r = self.client.get('/api/transporter/my-trips/completed/')
        pay = r.json()['data']['trips'][0]['payment']
        self.assertEqual(pay['status'], 'pending')
        self.assertEqual(pay['raw_status'], 'PENDING_COD')
        self.assertTrue(pay['can_confirm_cash'])

    def test_completed_list_includes_payment_captured(self):
        trip = self._trip(Trip.Status.COMPLETED)
        Payment.objects.create(
            trip=trip,
            payer=self.shipper,
            payee=self.driver,
            method=Payment.Method.WALLET,
            amount='100.00',
            status=Payment.Status.CAPTURED,
        )

        r = self.client.get('/api/transporter/my-trips/completed/')
        pay = r.json()['data']['trips'][0]['payment']
        self.assertEqual(pay['status'], 'completed')
        self.assertEqual(pay['raw_status'], 'CAPTURED')
        self.assertFalse(pay['can_confirm_cash'])

    def test_completed_list_payment_awaiting_shipper(self):
        trip = self._trip(Trip.Status.COMPLETED)

        r = self.client.get('/api/transporter/my-trips/completed/')
        pay = r.json()['data']['trips'][0]['payment']
        self.assertEqual(pay['status'], 'pending')
        self.assertIsNone(pay['raw_status'])
        self.assertTrue(pay['awaiting_shipper_payment'])
        self.assertFalse(pay['can_confirm_cash'])

    def test_completed_list_includes_payment_pending_card(self):
        trip = self._trip(Trip.Status.COMPLETED)
        Payment.objects.create(
            trip=trip,
            payer=self.shipper,
            payee=self.driver,
            method=Payment.Method.CARD,
            amount='100.00',
            status=Payment.Status.REQUIRES_ACTION,
        )

        r = self.client.get('/api/transporter/my-trips/completed/')
        pay = r.json()['data']['trips'][0]['payment']
        self.assertEqual(pay['status'], 'pending')
        self.assertEqual(pay['raw_status'], 'REQUIRES_ACTION')
        self.assertTrue(pay['can_confirm_card'])
        self.assertFalse(pay['awaiting_shipper_payment'])

    def test_active_excludes_assigned_and_completed(self):
        self._trip(Trip.Status.ASSIGNED)
        active = self._trip(Trip.Status.IN_TRANSIT)
        self._trip(Trip.Status.COMPLETED)

        r = self.client.get('/api/transporter/my-trips/active/')
        self.assertEqual(r.status_code, 200)
        ids = [t['id'] for t in r.json()['data']['trips']]
        self.assertEqual(ids, [active.id])
