<?php

namespace Tests\Tenant;

use App\Events\ServiceBookingConfirmedEvent;
use App\Facades\Settings;
use App\Jobs\ProcessIncomingBookingJob;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Str;
use Mtc\MercuryDataModels\Booking;
use Mtc\MercuryDataModels\BookingAvailability;
use Mtc\MercuryDataModels\Dealership;
use Tests\TenantTestCase;

class ProcessIncomingBookingJobTest extends TenantTestCase
{
    public function testProcessesBookingAndSetsIngestedAt()
    {
        Mail::fake();
        Event::fake();

        $booking = Booking::factory()->create([
            'uuid' => Str::random(16),
            'email' => 'customer@example.com',
            'ingested_at' => null,
            'first_name' => 'John',
            'last_name' => 'Doe',
            'phone_number' => '07123456789',
        ]);

        (new ProcessIncomingBookingJob($booking))->handle();

        $booking->refresh();
        $this->assertNotNull($booking->ingested_at);
    }

    public function testDispatchesServiceBookingConfirmedEvent()
    {
        Mail::fake();
        Event::fake([ServiceBookingConfirmedEvent::class]);

        $booking = Booking::factory()->create([
            'uuid' => Str::random(16),
            'email' => 'customer@example.com',
            'ingested_at' => null,
        ]);

        (new ProcessIncomingBookingJob($booking))->handle();

        Event::assertDispatched(ServiceBookingConfirmedEvent::class, function ($event) use ($booking) {
            return $event->booking->id === $booking->id;
        });
    }

    public function testSkipsAlreadyIngestedBooking()
    {
        Mail::fake();
        Event::fake([ServiceBookingConfirmedEvent::class]);

        $booking = Booking::factory()->create([
            'uuid' => Str::random(16),
            'email' => 'customer@example.com',
            'ingested_at' => now(),
        ]);

        (new ProcessIncomingBookingJob($booking))->handle();

        // Event should not be dispatched for already ingested booking
        Event::assertNotDispatched(ServiceBookingConfirmedEvent::class);
    }

    public function testSetsCustomerIdOnBooking()
    {
        Mail::fake();
        Event::fake();

        $booking = Booking::factory()->create([
            'uuid' => Str::random(16),
            'email' => 'customer@example.com',
            'ingested_at' => null,
            'customer_id' => null,
            'first_name' => 'Jane',
            'last_name' => 'Smith',
            'phone_number' => '07987654321',
        ]);

        (new ProcessIncomingBookingJob($booking))->handle();

        $booking->refresh();
        $this->assertNotNull($booking->ingested_at);
    }

    public function testUsesLocationEmailForRecipient()
    {
        Mail::fake();
        Event::fake();

        $dealership = Dealership::factory()->create();
        BookingAvailability::query()->create([
            'dealership_id' => $dealership->id,
            'email' => 'location@example.com',
            'number_of_bays' => 5,
        ]);

        $booking = Booking::factory()->create([
            'uuid' => Str::random(16),
            'email' => 'customer@example.com',
            'location_id' => $dealership->id,
            'ingested_at' => null,
        ]);

        (new ProcessIncomingBookingJob($booking))->handle();

        $booking->refresh();
        $this->assertNotNull($booking->ingested_at);
    }

    public function testFallsBackToContactEmailWhenNoLocationEmail()
    {
        Mail::fake();
        Event::fake();

        Settings::update('app-contact-contact_email', 'fallback@example.com');

        $booking = Booking::factory()->create([
            'uuid' => Str::random(16),
            'email' => 'customer@example.com',
            'location_id' => 999, // Non-existent location
            'ingested_at' => null,
        ]);

        (new ProcessIncomingBookingJob($booking))->handle();

        $booking->refresh();
        $this->assertNotNull($booking->ingested_at);
    }
}
