<?php

namespace Tests\Tenant;

use App\Facades\Settings;
use Carbon\Carbon;
use Illuminate\Support\Facades\Mail;
use Mtc\MercuryDataModels\Vehicle;
use Mtc\VehicleReservations\Console\Commands\SendFreeReservationExpiryReminders;
use Mtc\VehicleReservations\Mail\FreeReservationExpiryReminderCustomerMail;
use Mtc\VehicleReservations\Reservation;
use Tests\TenantTestCase;

class SendFreeReservationExpiryRemindersTest extends TenantTestCase
{
    private function makeWindowSetting(int $minutes): void
    {
        Settings::make([
            'tab' => 'Automotive',
            'section' => 'Sales',
            'group' => 'General',
            'name' => 'Free Reservation Reminder Window (Minutes)',
            'config_key' => 'sales-reservation-free-reminder-window-minutes',
            'type' => 'int',
            'value' => $minutes,
        ]);
    }

    public function testSendsReminderAndStampsWhenWithinWindow()
    {
        Mail::fake();
        $vehicle = Vehicle::factory()->create();
        $reservation = Reservation::factory()->free()->create([
            'vehicle_id' => $vehicle->id,
            'status' => 'confirmed',
            'email' => 'customer@example.test',
            'expires_at' => Carbon::now()->addMinutes(70),
            'expiry_reminder_sent_at' => null,
        ]);

        $this->artisan(SendFreeReservationExpiryReminders::class)->assertOk();

        Mail::assertSent(FreeReservationExpiryReminderCustomerMail::class);
        $this->assertNotNull($reservation->refresh()->expiry_reminder_sent_at);
    }

    public function testDoesNotSendWhenExpiryIsBeyondTheWindow()
    {
        Mail::fake();
        $vehicle = Vehicle::factory()->create();
        $reservation = Reservation::factory()->free()->create([
            'vehicle_id' => $vehicle->id,
            'status' => 'confirmed',
            'email' => 'customer@example.test',
            'expires_at' => Carbon::now()->addMinutes(180),
        ]);

        $this->artisan(SendFreeReservationExpiryReminders::class)->assertOk();

        Mail::assertNothingSent();
        $this->assertNull($reservation->refresh()->expiry_reminder_sent_at);
    }

    public function testDoesNotSendWhenAlreadyReminded()
    {
        Mail::fake();
        $vehicle = Vehicle::factory()->create();
        Reservation::factory()->free()->create([
            'vehicle_id' => $vehicle->id,
            'status' => 'confirmed',
            'email' => 'customer@example.test',
            'expires_at' => Carbon::now()->addMinutes(70),
            'expiry_reminder_sent_at' => Carbon::now()->subMinutes(5),
        ]);

        $this->artisan(SendFreeReservationExpiryReminders::class)->assertOk();

        Mail::assertNothingSent();
    }

    public function testDoesNotSendForAlreadyExpiredReservations()
    {
        Mail::fake();
        $vehicle = Vehicle::factory()->create();
        Reservation::factory()->free()->create([
            'vehicle_id' => $vehicle->id,
            'status' => 'confirmed',
            'email' => 'customer@example.test',
            'expires_at' => Carbon::now()->subMinutes(5),
        ]);

        $this->artisan(SendFreeReservationExpiryReminders::class)->assertOk();

        Mail::assertNothingSent();
    }

    public function testDoesNotSendForStandardReservations()
    {
        Mail::fake();
        $vehicle = Vehicle::factory()->create();
        Reservation::factory()->create([
            'vehicle_id' => $vehicle->id,
            'type' => Reservation::TYPE_STANDARD,
            'status' => 'confirmed',
            'email' => 'customer@example.test',
            'expires_at' => Carbon::now()->addMinutes(70),
        ]);

        $this->artisan(SendFreeReservationExpiryReminders::class)->assertOk();

        Mail::assertNothingSent();
    }

    public function testSkipsAndDoesNotStampWhenNoEmail()
    {
        Mail::fake();
        $vehicle = Vehicle::factory()->create();
        $reservation = Reservation::factory()->free()->create([
            'vehicle_id' => $vehicle->id,
            'status' => 'confirmed',
            'email' => null,
            'contact_number' => '07700900123',
            'expires_at' => Carbon::now()->addMinutes(70),
        ]);

        $this->artisan(SendFreeReservationExpiryReminders::class)->assertOk();

        Mail::assertNothingSent();
        $this->assertNull($reservation->refresh()->expiry_reminder_sent_at);
    }

    public function testRespectsConfiguredWindowSetting()
    {
        Mail::fake();
        $this->makeWindowSetting(30);

        $vehicle = Vehicle::factory()->create();
        $outside = Reservation::factory()->free()->create([
            'vehicle_id' => $vehicle->id,
            'status' => 'confirmed',
            'email' => 'outside@example.test',
            'expires_at' => Carbon::now()->addMinutes(60),
        ]);
        $inside = Reservation::factory()->free()->create([
            'vehicle_id' => $vehicle->id,
            'status' => 'confirmed',
            'email' => 'inside@example.test',
            'expires_at' => Carbon::now()->addMinutes(20),
        ]);

        $this->artisan(SendFreeReservationExpiryReminders::class)->assertOk();

        Mail::assertSent(FreeReservationExpiryReminderCustomerMail::class, 1);
        $this->assertNull($outside->refresh()->expiry_reminder_sent_at);
        $this->assertNotNull($inside->refresh()->expiry_reminder_sent_at);
    }
}
