<?php

namespace Tests\Tenant;

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

class BookingModelTest extends TenantTestCase
{
    public function testSetStatusWithValidStatusPending()
    {
        $booking = Booking::factory()->create([
            'uuid' => Str::random(16),
            'status' => BookingStatus::DRAFT->value,
        ]);

        $booking->setStatus(BookingStatus::PENDING->value);
        $booking->refresh();

        $this->assertEquals(BookingStatus::PENDING->value, $booking->status);
    }

    public function testSetStatusWithValidStatusConfirmed()
    {
        $booking = Booking::factory()->create([
            'uuid' => Str::random(16),
            'status' => BookingStatus::PENDING->value,
        ]);

        $booking->setStatus(BookingStatus::CONFIRMED->value);
        $booking->refresh();

        $this->assertEquals(BookingStatus::CONFIRMED->value, $booking->status);
    }

    public function testSetStatusWithValidStatusCompleted()
    {
        $booking = Booking::factory()->create([
            'uuid' => Str::random(16),
            'status' => BookingStatus::PENDING->value,
        ]);

        $booking->setStatus(BookingStatus::COMPLETED->value);
        $booking->refresh();

        $this->assertEquals(BookingStatus::COMPLETED->value, $booking->status);
    }

    public function testSetStatusWithValidStatusCancelled()
    {
        $booking = Booking::factory()->create([
            'uuid' => Str::random(16),
            'status' => BookingStatus::PENDING->value,
        ]);

        $booking->setStatus(BookingStatus::CANCELLED->value);
        $booking->refresh();

        $this->assertEquals(BookingStatus::CANCELLED->value, $booking->status);
    }

    public function testSetInvalidStatusThrowsValidationException()
    {
        $booking = Booking::factory()->create([
            'uuid' => Str::random(16),
            'status' => BookingStatus::PENDING->value,
        ]);

        $this->expectException(ValidationException::class);
        $booking->setStatus('invalid-status');
    }

    public function testTimeAttributeReturnsFormattedTime()
    {
        $booking = Booking::factory()->create([
            'uuid' => Str::random(16),
            'booking_time' => Carbon::parse('2026-03-01 14:30:00'),
        ]);

        $this->assertEquals('14:30', $booking->time);
    }

    public function testTimeAttributeReturnsNullWhenNoBookingTime()
    {
        $booking = Booking::factory()->create([
            'uuid' => Str::random(16),
            'booking_time' => null,
        ]);

        $this->assertNull($booking->time);
    }

    public function testPackagesRelationship()
    {
        $booking = Booking::factory()->create(['uuid' => Str::random(16)]);
        $package1 = ServicePackage::create(['name' => 'Package A', 'type' => 'package']);
        $package2 = ServicePackage::create(['name' => 'Package B', 'type' => 'add-on']);

        $booking->packages()->attach([$package1->id, $package2->id]);

        $booking->refresh();
        $this->assertCount(2, $booking->packages);
        $this->assertTrue($booking->packages->contains('id', $package1->id));
        $this->assertTrue($booking->packages->contains('id', $package2->id));
    }

    public function testLocationRelationship()
    {
        $dealership = Dealership::factory()->create(['name' => 'Test Location']);
        $booking = Booking::factory()->create([
            'uuid' => Str::random(16),
            'location_id' => $dealership->id,
        ]);

        $this->assertNotNull($booking->location);
        $this->assertEquals('Test Location', $booking->location->name);
        $this->assertEquals($dealership->id, $booking->location->id);
    }

    public function testDeliveryOptionRelationship()
    {
        $deliveryOption = BookingDeliveryOption::create([
            'name' => 'Collection Service',
            'description' => 'We come to you',
            'price' => 30.00,
        ]);
        $booking = Booking::factory()->create([
            'uuid' => Str::random(16),
            'delivery_option_id' => $deliveryOption->id,
        ]);

        $this->assertNotNull($booking->deliveryOption);
        $this->assertEquals('Collection Service', $booking->deliveryOption->name);
    }

    public function testVehicleDataCastToArray()
    {
        $vehicleData = [
            'make' => 'Toyota',
            'model' => 'Corolla',
            'colour' => 'Silver',
            'model_year' => 2022,
        ];
        $booking = Booking::factory()->create([
            'uuid' => Str::random(16),
            'vehicle_data' => $vehicleData,
        ]);

        $booking->refresh();
        $this->assertIsArray($booking->vehicle_data);
        $this->assertEquals('Toyota', $booking->vehicle_data['make']);
        $this->assertEquals('Corolla', $booking->vehicle_data['model']);
        $this->assertEquals('Silver', $booking->vehicle_data['colour']);
        $this->assertEquals(2022, $booking->vehicle_data['model_year']);
    }

    public function testDataFieldCastToArray()
    {
        $data = ['service_type' => 'annual', 'referral_source' => 'website'];
        $booking = Booking::factory()->create([
            'uuid' => Str::random(16),
            'data' => $data,
        ]);

        $booking->refresh();
        $this->assertIsArray($booking->data);
        $this->assertEquals('annual', $booking->data['service_type']);
        $this->assertEquals('website', $booking->data['referral_source']);
    }

    public function testTimeAppendedAttribute()
    {
        $booking = Booking::factory()->create([
            'uuid' => Str::random(16),
            'booking_time' => Carbon::parse('2026-05-10 09:00:00'),
        ]);

        $array = $booking->toArray();
        $this->assertArrayHasKey('time', $array);
        $this->assertEquals('09:00', $array['time']);
    }
}
