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

User = get_user_model()


class AdminAPITests(TestCase):
    def setUp(self):
        self.admin = User.objects.create_user(
            'admin@test.com',
            email='admin@test.com',
            password='secret',
            is_staff=True,
        )
        token, _ = Token.objects.get_or_create(user=self.admin)
        self.client = APIClient()
        self.client.credentials(HTTP_AUTHORIZATION=f'Bearer {token.key}')

        self.shipper = User.objects.create_user(
            'shipper@test.com',
            email='shipper@test.com',
            password='secret',
        )
        UserRole.objects.create(user=self.shipper, role=UserRole.Role.SHIPPER, phone='', language='en')
        self.transporter = User.objects.create_user(
            'transporter@test.com',
            email='transporter@test.com',
            password='secret',
        )
        UserRole.objects.create(
            user=self.transporter,
            role=UserRole.Role.TRANSPORTER,
            phone='',
            language='en',
        )
        self.shipment = Shipment.objects.create(
            shipper=self.shipper,
            pickup_address='A',
            delivery_address='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.transporter,
            amount=Decimal('100.00'),
            status=Bid.Status.ACCEPTED,
        )
        self.trip = Trip.objects.create(
            shipment=self.shipment,
            accepted_bid=self.bid,
            transporter=self.transporter,
            status=Trip.Status.ASSIGNED,
        )
        Payment.objects.create(
            trip=self.trip,
            payer=self.shipper,
            payee=self.transporter,
            method=Payment.Method.WALLET,
            amount=Decimal('50.00'),
            currency='USD',
            status=Payment.Status.CAPTURED,
        )

    def test_dashboard_returns_aggregates(self):
        r = self.client.get('/api/admin/dashboard/')
        self.assertEqual(r.status_code, 200)
        data = r.json()['data']
        self.assertIn('trips', data)
        self.assertIn('shipments', data)
        self.assertEqual(data['revenue']['captured_payments_count'], 1)
        self.assertIsNone(data['commission'])

    def test_trip_status_override_creates_audit_and_syncs_shipment(self):
        url = f'/api/admin/trips/{self.trip.id}/status-override/'
        r = self.client.post(
            url,
            {'new_status': Trip.Status.EN_ROUTE, 'justification': 'Support ticket #1'},
            format='json',
        )
        self.assertEqual(r.status_code, 200)
        self.trip.refresh_from_db()
        self.shipment.refresh_from_db()
        self.assertEqual(self.trip.status, Trip.Status.EN_ROUTE)
        self.assertEqual(self.shipment.status, Shipment.Status.EN_ROUTE)
        self.assertEqual(AdminTripAction.objects.filter(trip=self.trip).count(), 1)
        act = AdminTripAction.objects.get(trip=self.trip)
        self.assertEqual(act.previous_status, Trip.Status.ASSIGNED)
        self.assertEqual(act.new_status, Trip.Status.EN_ROUTE)
        self.assertEqual(act.performed_by_id, self.admin.id)

    def test_trip_closed_sets_shipment_closed(self):
        self.client.post(
            f'/api/admin/trips/{self.trip.id}/status-override/',
            {'new_status': Trip.Status.CLOSED, 'justification': 'Cancelled by ops'},
            format='json',
        )
        self.shipment.refresh_from_db()
        self.assertEqual(self.shipment.status, Shipment.Status.CLOSED)
