<?php

namespace Tests\Tenant;

use Carbon\Carbon;
use Mtc\MercuryDataModels\BookingAvailability;
use Mtc\MercuryDataModels\BookingAvailabilityHoliday;
use Mtc\MercuryDataModels\Dealership;
use Tests\TenantTestCase;
use Tests\UserForTenant;

class ServiceAvailabilityControllerTest extends TenantTestCase
{
    use UserForTenant;

    public function testListAvailabilityReturnsDealerships()
    {
        Dealership::factory()->create(['name' => 'Dealer A']);
        Dealership::factory()->create(['name' => 'Dealer B']);

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

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

    public function testListAvailabilityShowsActiveStatus()
    {
        $activeDealership = Dealership::factory()->create(['name' => 'Active Dealer']);
        BookingAvailability::create([
            'dealership_id' => $activeDealership->id,
            'active' => true,
            'number_of_bays' => 5,
        ]);

        $inactiveDealership = Dealership::factory()->create(['name' => 'Inactive Dealer']);

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

        $response->assertStatus(200);
        $dealers = collect($response->json());

        $active = $dealers->firstWhere('id', $activeDealership->id);
        $this->assertEquals('Service booking active', $active['metaItems']['active']);
        $this->assertTrue($active['has_availability']);

        $inactive = $dealers->firstWhere('id', $inactiveDealership->id);
        $this->assertEquals('', $inactive['metaItems']['active']);
        $this->assertFalse($inactive['has_availability']);
    }

    public function testShowAvailabilityReturnsDealershipWithAvailabilityData()
    {
        $dealership = Dealership::factory()->create(['name' => 'Test Dealer']);
        BookingAvailability::create([
            'dealership_id' => $dealership->id,
            'active' => true,
            'email' => 'service@dealer.com',
            'number_of_bays' => 4,
            'time_windows' => ['09:00', '11:00', '14:00'],
            'mondays' => true,
            'tuesdays' => true,
            'wednesdays' => true,
            'thursdays' => true,
            'fridays' => true,
            'saturdays' => false,
            'sundays' => false,
            'min_days_in_future_for_booking' => 1,
            'max_days_in_future_for_booking' => 60,
        ]);

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

        $response->assertStatus(200);

        $this->assertEquals($dealership->id, $response->json('location.id'));
        $this->assertEquals('Test Dealer', $response->json('location.name'));

        $availability = $response->json('availability');
        $this->assertTrue($availability['active']);
        $this->assertEquals('service@dealer.com', $availability['email']);
        $this->assertEquals(4, $availability['number_of_bays']);
        $this->assertEquals(['09:00', '11:00', '14:00'], $availability['time_windows']);
        $this->assertTrue($availability['mondays']);
        $this->assertFalse($availability['saturdays']);
        $this->assertEquals(1, $availability['min_days_in_future_for_booking']);
        $this->assertEquals(60, $availability['max_days_in_future_for_booking']);
    }

    public function testShowAvailabilityIncludesUpcomingHolidays()
    {
        $dealership = Dealership::factory()->create();
        $availability = BookingAvailability::create([
            'dealership_id' => $dealership->id,
            'active' => true,
            'number_of_bays' => 3,
        ]);

        // Future holiday - should appear
        BookingAvailabilityHoliday::create([
            'availability_id' => $availability->id,
            'holiday_date' => Carbon::now()->addMonth()->format('Y-m-d'),
        ]);
        // Past holiday - should not appear
        BookingAvailabilityHoliday::create([
            'availability_id' => $availability->id,
            'holiday_date' => Carbon::now()->subMonth()->format('Y-m-d'),
        ]);

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

        $response->assertStatus(200);
        $holidays = $response->json('availability.holidays');
        $this->assertCount(1, $holidays);
    }

    public function testUpdateCreatesNewAvailabilityForDealership()
    {
        $dealership = Dealership::factory()->create();
        $this->assertEquals(0, BookingAvailability::count());

        $response = $this->actingAs($this->getUser())
            ->putJson('/api/service-bookings/availability/' . $dealership->id, [
                'active' => true,
                'email' => 'service@example.com',
                'number_of_bays' => 6,
                'time_windows' => ['09:00', '13:00'],
                'mondays' => true,
                'tuesdays' => true,
                'wednesdays' => true,
                'thursdays' => true,
                'fridays' => true,
                'saturdays' => false,
                'sundays' => false,
                'min_days_in_future_for_booking' => 2,
                'max_days_in_future_for_booking' => 90,
                'holidays' => [],
            ]);

        $response->assertStatus(200);
        $this->assertEquals(1, BookingAvailability::count());

        $availability = BookingAvailability::first();
        $this->assertEquals($dealership->id, $availability->dealership_id);
        $this->assertTrue($availability->active);
        $this->assertEquals('service@example.com', $availability->email);
        $this->assertEquals(6, $availability->number_of_bays);
        $this->assertEquals(['09:00', '13:00'], $availability->time_windows);
        $this->assertTrue($availability->mondays);
        $this->assertFalse($availability->saturdays);
    }

    public function testUpdateExistingAvailabilityModifiesFields()
    {
        $dealership = Dealership::factory()->create();
        BookingAvailability::create([
            'dealership_id' => $dealership->id,
            'active' => false,
            'number_of_bays' => 2,
            'email' => 'old@example.com',
        ]);

        $response = $this->actingAs($this->getUser())
            ->putJson('/api/service-bookings/availability/' . $dealership->id, [
                'active' => true,
                'email' => 'new@example.com',
                'number_of_bays' => 8,
                'holidays' => [],
            ]);

        $response->assertStatus(200);
        $this->assertEquals(1, BookingAvailability::count());

        $availability = BookingAvailability::first();
        $this->assertTrue($availability->active);
        $this->assertEquals('new@example.com', $availability->email);
        $this->assertEquals(8, $availability->number_of_bays);
    }

    public function testUpdateAvailabilityAllocatesHolidays()
    {
        $dealership = Dealership::factory()->create();

        $futureDate1 = Carbon::now()->addWeeks(2)->format('Y-m-d');
        $futureDate2 = Carbon::now()->addWeeks(4)->format('Y-m-d');

        $response = $this->actingAs($this->getUser())
            ->putJson('/api/service-bookings/availability/' . $dealership->id, [
                'active' => true,
                'email' => '',
                'number_of_bays' => 3,
                'holidays' => [$futureDate1, $futureDate2],
            ]);

        $response->assertStatus(200);
        $this->assertEquals(2, BookingAvailabilityHoliday::count());

        $holidayDates = BookingAvailabilityHoliday::pluck('holiday_date')->map(fn ($d) => Carbon::parse($d)->format('Y-m-d'))->toArray();
        $this->assertContains($futureDate1, $holidayDates);
        $this->assertContains($futureDate2, $holidayDates);
    }

    public function testUpdateAvailabilityValidatesRequiredFields()
    {
        $dealership = Dealership::factory()->create();

        $response = $this->actingAs($this->getUser())
            ->putJson('/api/service-bookings/availability/' . $dealership->id, []);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['active', 'email', 'number_of_bays']);
    }

    public function testUpdateAvailabilityValidatesTimeWindowFormat()
    {
        $dealership = Dealership::factory()->create();

        $response = $this->actingAs($this->getUser())
            ->putJson('/api/service-bookings/availability/' . $dealership->id, [
                'active' => true,
                'email' => '',
                'number_of_bays' => 3,
                'time_windows' => ['not-a-time', '25:99'],
            ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['time_windows.0', 'time_windows.1']);
    }

    public function testUpdateAvailabilityValidatesHolidayDateFormat()
    {
        $dealership = Dealership::factory()->create();

        $response = $this->actingAs($this->getUser())
            ->putJson('/api/service-bookings/availability/' . $dealership->id, [
                'active' => true,
                'email' => '',
                'number_of_bays' => 3,
                'holidays' => ['not-a-date', '31/12/2026'],
            ]);

        $response->assertStatus(422);
        $response->assertJsonValidationErrors(['holidays.0', 'holidays.1']);
    }
}
