<?php

namespace Tests\Feature\Admin;

use App\Models\BookingStatus;
use App\Models\Company;
use App\Models\Currency;
use App\Models\Customer;
use App\Models\Driver;
use App\Models\Role;
use App\Models\User;
use App\Models\VehicleType;
use App\Services\GoogleMapsService;
use Database\Seeders\BookingStatusSeeder;
use Database\Seeders\PermissionSeeder;
use Database\Seeders\RoleSeeder;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

/**
 * The core dispatch path: creating a booking from the admin console. Fare
 * and distance are always server-computed (App\Services\FareCalculator,
 * App\Services\GoogleMapsService) rather than trusted from the client, so
 * GoogleMapsService is faked here rather than hitting the real Google API —
 * this test is about the booking/fare logic, not network integration.
 */
class BookingCreationTest extends TestCase
{
    use RefreshDatabase;

    protected function setUp(): void
    {
        parent::setUp();

        $this->seed(BookingStatusSeeder::class);
        $this->seed(PermissionSeeder::class);
        $this->seed(RoleSeeder::class);
    }

    public function test_creating_a_single_vehicle_booking_computes_the_fare_server_side(): void
    {
        $company = Company::create(['name' => 'Test Co', 'slug' => 'test-co', 'code' => '501']);
        $currency = Currency::create(['name' => 'Pound Sterling', 'code' => 'GBP', 'symbol' => '£', 'decimal_places' => 2, 'is_active' => true]);
        $admin = $this->makeCompanyAdmin($company);
        $customer = Customer::create(['company_id' => $company->id, 'name' => 'Jordan Blake', 'phone' => '07700900000', 'status' => 'active']);
        $vehicleType = VehicleType::create([
            'company_id' => $company->id, 'currency_id' => $currency->id, 'name' => 'Saloon',
            'capacity' => 4, 'base_fare' => 3, 'per_distance_rate' => 1.5,
        ]);

        $this->mock(GoogleMapsService::class, function ($mock) {
            $mock->shouldReceive('distanceAndDuration')->andReturn(['distance' => 10.0, 'duration_minutes' => 20]);
        });

        $response = $this->actingAs($admin)->post(route('admin.bookings.store'), [
            'customer_id' => (string) $customer->id,
            'vehicles' => [['vehicle_type_id' => $vehicleType->id, 'quantity' => 1]],
            'pickup_address' => '1 Test St',
            'dropoff_address' => '2 Test Ave',
            'pickup_datetime' => now()->addHour()->format('Y-m-d H:i:s'),
            'passengers' => 2,
            'luggage' => 0,
        ]);

        $response->assertRedirect();
        $response->assertSessionHas('success');

        $this->assertDatabaseHas('bookings', [
            'company_id' => $company->id,
            'customer_id' => $customer->id,
            'fare_amount' => 18.00, // base_fare 3 + (per_distance_rate 1.5 * distance 10)
            'distance' => 10.00,
        ]);

        $newStatusId = BookingStatus::where('name', 'Unassigned')->value('id');
        $this->assertDatabaseHas('bookings', ['customer_id' => $customer->id, 'status_id' => $newStatusId]);
    }

    public function test_a_multi_vehicle_booking_cannot_have_a_driver_preassigned(): void
    {
        $company = Company::create(['name' => 'Test Co', 'slug' => 'test-co', 'code' => '501']);
        $currency = Currency::create(['name' => 'Pound Sterling', 'code' => 'GBP', 'symbol' => '£', 'decimal_places' => 2, 'is_active' => true]);
        $admin = $this->makeCompanyAdmin($company);
        $customer = Customer::create(['company_id' => $company->id, 'name' => 'Jordan Blake', 'phone' => '07700900000', 'status' => 'active']);
        $vehicleType = VehicleType::create([
            'company_id' => $company->id, 'currency_id' => $currency->id, 'name' => 'Saloon',
            'capacity' => 4, 'base_fare' => 3, 'per_distance_rate' => 1.5,
        ]);
        $driver = Driver::create(['company_id' => $company->id, 'first_name' => 'Sam', 'last_name' => 'Ollero', 'status' => 'active']);

        $response = $this->actingAs($admin)->post(route('admin.bookings.store'), [
            'customer_id' => (string) $customer->id,
            'vehicles' => [['vehicle_type_id' => $vehicleType->id, 'quantity' => 2]],
            'driver_id' => $driver->id,
            'pickup_address' => '1 Test St',
            'dropoff_address' => '2 Test Ave',
            'pickup_datetime' => now()->addHour()->format('Y-m-d H:i:s'),
            'passengers' => 2,
            'luggage' => 0,
        ]);

        $response->assertSessionHasErrors('driver_id');
        $this->assertDatabaseCount('bookings', 0);
    }

    private function makeCompanyAdmin(Company $company): User
    {
        return User::factory()->create([
            'company_id' => $company->id,
            'role_id' => Role::where('name', 'company_admin')->value('id'),
            'status' => 'active',
        ]);
    }
}
