<?php

namespace Tests\Tenant;

use Carbon\Carbon;
use Illuminate\Support\Str;
use Mtc\MercuryDataModels\Booking;
use Mtc\MercuryDataModels\BookingDeliveryOption;
use Mtc\MercuryDataModels\BookingStatus;
use Mtc\MercuryDataModels\Dealership;
use Mtc\MercuryDataModels\ServicePackage;
use Tests\TenantTestCase;
use Tests\UserForTenant;

class BookingControllerTest extends TenantTestCase
{
    use UserForTenant;

    public function testListBookingsReturnsPaginatedResults()
    {
        Booking::factory()->count(3)->create([
            'uuid' => fn () => Str::random(16),
            'status' => BookingStatus::PENDING->value,
        ]);

        $response = $this->actingAs($this->getUser())
            ->getJson('/api/service-bookings/bookings');

        $response->assertStatus(200);
        $response->assertJsonStructure([
            'data',
            'current_page',
            'per_page',
            'total',
        ]);
        $this->assertCount(3, $response->json('data'));
    }

    public function testListBookingsExcludesDraftAndCancelled()
    {
        $pending = Booking::factory()->create([
            'uuid' => Str::random(16),
            'status' => BookingStatus::PENDING->value,
            'first_name' => 'Pending',
        ]);
        $confirmed = Booking::factory()->create([
            'uuid' => Str::random(16),
            'status' => BookingStatus::CONFIRMED->value,
            'first_name' => 'Confirmed',
        ]);
        $completed = Booking::factory()->create([
            'uuid' => Str::random(16),
            'status' => BookingStatus::COMPLETED->value,
            'first_name' => 'Completed',
        ]);
        Booking::factory()->create([
            'uuid' => Str::random(16),
            'status' => BookingStatus::DRAFT->value,
            'first_name' => 'Draft',
        ]);
        Booking::factory()->create([
            'uuid' => Str::random(16),
            'status' => BookingStatus::CANCELLED->value,
            'first_name' => 'Cancelled',
        ]);

        $response = $this->actingAs($this->getUser())
            ->getJson('/api/service-bookings/bookings');

        $response->assertStatus(200);
        $this->assertCount(3, $response->json('data'));

        $returnedIds = collect($response->json('data'))->pluck('id')->toArray();
        $this->assertContains($pending->id, $returnedIds);
        $this->assertContains($confirmed->id, $returnedIds);
        $this->assertContains($completed->id, $returnedIds);
    }

    public function testListBookingsFilterByCustomerId()
    {
        $targetCustomerId = 42;
        Booking::factory()->create([
            'uuid' => Str::random(16),
            'customer_id' => $targetCustomerId,
            'status' => BookingStatus::PENDING->value,
        ]);
        Booking::factory()->create([
            'uuid' => Str::random(16),
            'customer_id' => $targetCustomerId,
            'status' => BookingStatus::CONFIRMED->value,
        ]);
        Booking::factory()->create([
            'uuid' => Str::random(16),
            'customer_id' => 99,
            'status' => BookingStatus::PENDING->value,
        ]);

        $response = $this->actingAs($this->getUser())
            ->getJson('/api/service-bookings/bookings?customer_id=' . $targetCustomerId);

        $response->assertStatus(200);
        $this->assertCount(2, $response->json('data'));

        foreach ($response->json('data') as $booking) {
            $this->assertEquals($targetCustomerId, $booking['customer_id']);
        }
    }

    public function testListBookingsSearchByFirstName()
    {
        Booking::factory()->create([
            'uuid' => Str::random(16),
            'first_name' => 'Alexander',
            'last_name' => 'Smith',
            'status' => BookingStatus::PENDING->value,
        ]);
        Booking::factory()->create([
            'uuid' => Str::random(16),
            'first_name' => 'John',
            'last_name' => 'Doe',
            'status' => BookingStatus::PENDING->value,
        ]);

        $response = $this->actingAs($this->getUser())
            ->getJson('/api/service-bookings/bookings?search=Alexander');

        $response->assertStatus(200);
        $this->assertCount(1, $response->json('data'));
        $this->assertEquals('Alexander', $response->json('data.0.first_name'));
    }

    public function testListBookingsSearchByEmail()
    {
        Booking::factory()->create([
            'uuid' => Str::random(16),
            'email' => 'unique-target@example.com',
            'status' => BookingStatus::PENDING->value,
        ]);
        Booking::factory()->create([
            'uuid' => Str::random(16),
            'email' => 'other@example.com',
            'status' => BookingStatus::PENDING->value,
        ]);

        $response = $this->actingAs($this->getUser())
            ->getJson('/api/service-bookings/bookings?search=unique-target');

        $response->assertStatus(200);
        $this->assertCount(1, $response->json('data'));
        $this->assertEquals('unique-target@example.com', $response->json('data.0.email'));
    }

    public function testListBookingsSearchByRegistrationNumber()
    {
        Booking::factory()->create([
            'uuid' => Str::random(16),
            'registration_number' => 'AB12CDE',
            'status' => BookingStatus::PENDING->value,
        ]);
        Booking::factory()->create([
            'uuid' => Str::random(16),
            'registration_number' => 'XY98ZZZ',
            'status' => BookingStatus::PENDING->value,
        ]);

        $response = $this->actingAs($this->getUser())
            ->getJson('/api/service-bookings/bookings?search=AB12CDE');

        $response->assertStatus(200);
        $this->assertCount(1, $response->json('data'));
        $this->assertEquals('AB12CDE', $response->json('data.0.registration_number'));
    }

    public function testListBookingsResponseHasTitleAndDescription()
    {
        $dealership = Dealership::factory()->create(['name' => 'Main Dealer']);
        Booking::factory()->create([
            'uuid' => Str::random(16),
            'first_name' => 'Jane',
            'last_name' => 'Doe',
            'registration_number' => 'AB12CDE',
            'vehicle_data' => ['make' => 'BMW', 'model' => '3 Series'],
            'booking_time' => Carbon::parse('2026-03-01 09:00:00'),
            'location_id' => $dealership->id,
            'status' => BookingStatus::PENDING->value,
        ]);

        $response = $this->actingAs($this->getUser())
            ->getJson('/api/service-bookings/bookings');

        $response->assertStatus(200);
        $booking = $response->json('data.0');
        $this->assertEquals('Jane Doe', $booking['title']);
        $this->assertStringContainsString('AB12CDE', $booking['description']);
        $this->assertStringContainsString('BMW', $booking['description']);
        $this->assertStringContainsString('3 Series', $booking['description']);
        $this->assertEquals('Main Dealer', $booking['metaItems']['location']);
        $this->assertNotEmpty($booking['metaItems']['time']);
    }

    public function testShowBookingReturnsBookingWithRelations()
    {
        $dealership = Dealership::factory()->create(['name' => 'Test Dealer']);
        $deliveryOption = BookingDeliveryOption::create([
            'name' => 'Collection',
            'description' => 'We collect your car',
            'price' => 25.00,
        ]);
        $package = ServicePackage::create([
            'name' => 'Full Service',
            'type' => 'package',
            'price' => 199.99,
        ]);

        $booking = Booking::factory()->create([
            'uuid' => Str::random(16),
            'first_name' => 'Peter',
            'last_name' => 'Parker',
            'email' => 'peter@example.com',
            'registration_number' => 'SP1DER',
            'vehicle_data' => ['make' => 'Ford', 'model' => 'Focus', 'colour' => 'Red', 'model_year' => 2023],
            'location_id' => $dealership->id,
            'delivery_option_id' => $deliveryOption->id,
            'status' => BookingStatus::CONFIRMED->value,
        ]);
        $booking->packages()->attach($package->id);

        $response = $this->actingAs($this->getUser())
            ->getJson('/api/service-bookings/bookings/' . $booking->id);

        $response->assertStatus(200);
        $this->assertEquals('Peter', $response->json('first_name'));
        $this->assertEquals('Parker', $response->json('last_name'));
        $this->assertEquals('peter@example.com', $response->json('email'));
        $this->assertEquals('SP1DER', $response->json('registration_number'));
        $this->assertEquals(BookingStatus::CONFIRMED->value, $response->json('status'));

        // Verify relations loaded
        $this->assertEquals('Test Dealer', $response->json('location.name'));
        $this->assertEquals('Collection', $response->json('delivery_option.name'));
        $this->assertCount(1, $response->json('packages'));
        $this->assertEquals('Full Service', $response->json('packages.0.name'));
    }

    public function testShowBookingIncludesPreviewImage()
    {
        $booking = Booking::factory()->create([
            'uuid' => Str::random(16),
            'vehicle_data' => [
                'make' => 'Audi',
                'model' => 'A4',
                'colour' => 'Blue',
                'model_year' => 2024,
            ],
            'status' => BookingStatus::PENDING->value,
        ]);

        $response = $this->actingAs($this->getUser())
            ->getJson('/api/service-bookings/bookings/' . $booking->id);

        $response->assertStatus(200);
        $previewImage = $response->json('preview_image');
        $this->assertStringContainsString('cdn.imagin.studio', $previewImage);
        $this->assertStringContainsString('make=Audi', $previewImage);
        $this->assertStringContainsString('modelFamily=A4', $previewImage);
        $this->assertStringContainsString('paintdescription=Blue', $previewImage);
        $this->assertStringContainsString('modelYear=2024', $previewImage);
    }

    public function testShowBookingTransformsDataKeysToTitleCase()
    {
        $booking = Booking::factory()->create([
            'uuid' => Str::random(16),
            'data' => [
                'service_type' => 'MOT',
                'additional_notes' => 'Please check brakes',
            ],
            'status' => BookingStatus::PENDING->value,
        ]);

        $response = $this->actingAs($this->getUser())
            ->getJson('/api/service-bookings/bookings/' . $booking->id);

        $response->assertStatus(200);
        $data = $response->json('data');
        $this->assertArrayHasKey('Service Type', $data);
        $this->assertArrayHasKey('Additional Notes', $data);
        $this->assertEquals('MOT', $data['Service Type']);
    }

    public function testUpdateBookingModifiesFields()
    {
        $booking = Booking::factory()->create([
            'uuid' => Str::random(16),
            'first_name' => 'Original',
            'last_name' => 'Name',
            'email' => 'old@example.com',
            'mileage' => 50000,
            'status' => BookingStatus::PENDING->value,
        ]);

        $response = $this->actingAs($this->getUser())
            ->putJson('/api/service-bookings/bookings/' . $booking->id, [
                'first_name' => 'Updated',
                'last_name' => 'Person',
                'email' => 'new@example.com',
                'mileage' => 55000,
            ]);

        $response->assertStatus(200);

        $booking->refresh();
        $this->assertEquals('Updated', $booking->first_name);
        $this->assertEquals('Person', $booking->last_name);
        $this->assertEquals('new@example.com', $booking->email);
        $this->assertEquals(55000, $booking->mileage);
    }
}
