<?php

use App\Enums\ConsultationStatus;
use App\Mail\BookingSubmittedMail;
use App\Mail\NewBookingAdminEmail;
use App\Models\AdminLog;
use App\Models\Consultation;
use App\Models\User;
use App\Models\WorkingHour;
use Illuminate\Support\Facades\Mail;
use Livewire\Volt\Volt;

beforeEach(function () {
    // Setup working hours for Monday (day 1)
    WorkingHour::factory()->create([
        'day_of_week' => 1,
        'start_time' => '09:00',
        'end_time' => '17:00',
        'is_active' => true,
    ]);
});

// Navigation Tests
test('client sees book now link in navigation', function () {
    $client = User::factory()->individual()->create();

    $this->actingAs($client)
        ->get(route('client.dashboard'))
        ->assertOk()
        ->assertSee(__('navigation.book_now'));
});

test('book now link navigates to booking page', function () {
    $client = User::factory()->individual()->create();

    $this->actingAs($client)
        ->get(route('client.consultations.book'))
        ->assertOk();
});

test('admin does not see book now link', function () {
    $admin = User::factory()->admin()->create();

    $this->actingAs($admin)
        ->get(route('admin.dashboard'))
        ->assertOk()
        ->assertDontSee(__('navigation.book_now'));
});

test('guest cannot access booking form', function () {
    $this->get(route('client.consultations.book'))
        ->assertRedirect(route('login'));
});

test('authenticated client can access booking form', function () {
    $client = User::factory()->individual()->create();

    $this->actingAs($client)
        ->get(route('client.consultations.book'))
        ->assertOk();
});

test('authenticated client can submit booking request', function () {
    Mail::fake();

    $client = User::factory()->individual()->create();
    User::factory()->admin()->create();
    $monday = now()->next('Monday')->format('Y-m-d');

    $this->actingAs($client);

    Volt::test('client.consultations.book')
        ->call('selectSlot', $monday, '10:00')
        ->set('problemSummary', 'I need legal advice regarding a contract dispute with my employer.')
        ->call('showConfirm')
        ->assertSet('showConfirmation', true)
        ->call('submit')
        ->assertRedirect(route('client.consultations.index'));

    expect(Consultation::where('user_id', $client->id)->exists())->toBeTrue();

    Mail::assertQueued(BookingSubmittedMail::class);
    Mail::assertQueued(NewBookingAdminEmail::class);
});

test('booking is created with pending status', function () {
    Mail::fake();

    $client = User::factory()->individual()->create();
    $monday = now()->next('Monday')->format('Y-m-d');

    $this->actingAs($client);

    Volt::test('client.consultations.book')
        ->call('selectSlot', $monday, '10:00')
        ->set('problemSummary', 'I need legal advice regarding a contract dispute.')
        ->call('showConfirm')
        ->call('submit');

    $consultation = Consultation::where('user_id', $client->id)->first();
    expect($consultation->status)->toBe(ConsultationStatus::Pending);
});

test('problem summary is required', function () {
    $client = User::factory()->individual()->create();
    $monday = now()->next('Monday')->format('Y-m-d');

    $this->actingAs($client);

    Volt::test('client.consultations.book')
        ->call('selectSlot', $monday, '10:00')
        ->set('problemSummary', '')
        ->call('showConfirm')
        ->assertHasErrors(['problemSummary' => 'required']);
});

test('problem summary must be at least 20 characters', function () {
    $client = User::factory()->individual()->create();
    $monday = now()->next('Monday')->format('Y-m-d');

    $this->actingAs($client);

    Volt::test('client.consultations.book')
        ->call('selectSlot', $monday, '10:00')
        ->set('problemSummary', 'Too short')
        ->call('showConfirm')
        ->assertHasErrors(['problemSummary' => 'min']);
});

test('problem summary cannot exceed 2000 characters', function () {
    $client = User::factory()->individual()->create();
    $monday = now()->next('Monday')->format('Y-m-d');

    $this->actingAs($client);

    Volt::test('client.consultations.book')
        ->call('selectSlot', $monday, '10:00')
        ->set('problemSummary', str_repeat('a', 2001))
        ->call('showConfirm')
        ->assertHasErrors(['problemSummary' => 'max']);
});

test('client cannot book more than once per day', function () {
    $client = User::factory()->individual()->create();
    $monday = now()->next('Monday')->format('Y-m-d');

    // Create existing booking
    Consultation::factory()->pending()->create([
        'user_id' => $client->id,
        'booking_date' => $monday,
        'booking_time' => '09:00',
    ]);

    $this->actingAs($client);

    Volt::test('client.consultations.book')
        ->call('selectSlot', $monday, '10:00')
        ->set('problemSummary', 'I need legal advice regarding a contract dispute.')
        ->call('showConfirm')
        ->assertHasErrors(['selectedDate']);
});

test('client can book on different day if already booked on another', function () {
    Mail::fake();

    $client = User::factory()->individual()->create();
    $monday = now()->next('Monday')->format('Y-m-d');
    $nextMonday = now()->next('Monday')->addWeek()->format('Y-m-d');

    // Create existing booking for this Monday
    Consultation::factory()->pending()->create([
        'user_id' => $client->id,
        'booking_date' => $monday,
        'booking_time' => '09:00',
    ]);

    $this->actingAs($client);

    Volt::test('client.consultations.book')
        ->call('selectSlot', $nextMonday, '10:00')
        ->set('problemSummary', 'I need legal advice regarding a contract dispute.')
        ->call('showConfirm')
        ->assertSet('showConfirmation', true);
});

test('client cannot book unavailable slot', function () {
    $client = User::factory()->individual()->create();
    $monday = now()->next('Monday')->format('Y-m-d');

    // Create booking that takes the slot
    Consultation::factory()->approved()->create([
        'booking_date' => $monday,
        'booking_time' => '10:00',
    ]);

    $this->actingAs($client);

    Volt::test('client.consultations.book')
        ->call('selectSlot', $monday, '10:00')
        ->set('problemSummary', 'I need legal advice regarding a contract dispute.')
        ->call('showConfirm')
        ->assertHasErrors(['selectedTime']);
});

test('confirmation step displays before final submission', function () {
    $client = User::factory()->individual()->create();
    $monday = now()->next('Monday')->format('Y-m-d');

    $this->actingAs($client);

    Volt::test('client.consultations.book')
        ->call('selectSlot', $monday, '10:00')
        ->set('problemSummary', 'I need legal advice regarding a contract dispute.')
        ->assertSet('showConfirmation', false)
        ->call('showConfirm')
        ->assertSet('showConfirmation', true);
});

test('user can go back from confirmation to edit', function () {
    $client = User::factory()->individual()->create();
    $monday = now()->next('Monday')->format('Y-m-d');

    $this->actingAs($client);

    Volt::test('client.consultations.book')
        ->call('selectSlot', $monday, '10:00')
        ->set('problemSummary', 'I need legal advice regarding a contract dispute.')
        ->call('showConfirm')
        ->assertSet('showConfirmation', true)
        ->set('showConfirmation', false)
        ->assertSet('showConfirmation', false);
});

test('user can clear slot selection', function () {
    $client = User::factory()->individual()->create();
    $monday = now()->next('Monday')->format('Y-m-d');

    $this->actingAs($client);

    Volt::test('client.consultations.book')
        ->call('selectSlot', $monday, '10:00')
        ->assertSet('selectedDate', $monday)
        ->assertSet('selectedTime', '10:00')
        ->call('clearSelection')
        ->assertSet('selectedDate', null)
        ->assertSet('selectedTime', null);
});

test('success message shown after submission', function () {
    Mail::fake();

    $client = User::factory()->individual()->create();
    $monday = now()->next('Monday')->format('Y-m-d');

    $this->actingAs($client);

    Volt::test('client.consultations.book')
        ->call('selectSlot', $monday, '10:00')
        ->set('problemSummary', 'I need legal advice regarding a contract dispute.')
        ->call('showConfirm')
        ->call('submit')
        ->assertSessionHas('success');
});

test('audit log entry is created on booking submission', function () {
    Mail::fake();

    $client = User::factory()->individual()->create();
    $monday = now()->next('Monday')->format('Y-m-d');

    $this->actingAs($client);

    Volt::test('client.consultations.book')
        ->call('selectSlot', $monday, '10:00')
        ->set('problemSummary', 'I need legal advice regarding a contract dispute.')
        ->call('showConfirm')
        ->call('submit');

    $consultation = Consultation::where('user_id', $client->id)->first();

    expect(AdminLog::query()
        ->where('action', 'create')
        ->where('target_type', 'consultation')
        ->where('target_id', $consultation->id)
        ->whereNull('admin_id')
        ->exists()
    )->toBeTrue();
});

test('emails are sent to client and admin after submission', function () {
    Mail::fake();

    $client = User::factory()->individual()->create();
    $admin = User::factory()->admin()->create();
    $monday = now()->next('Monday')->format('Y-m-d');

    $this->actingAs($client);

    Volt::test('client.consultations.book')
        ->call('selectSlot', $monday, '10:00')
        ->set('problemSummary', 'I need legal advice regarding a contract dispute.')
        ->call('showConfirm')
        ->call('submit');

    Mail::assertQueued(BookingSubmittedMail::class, function ($mail) use ($client) {
        return $mail->hasTo($client->email);
    });

    Mail::assertQueued(NewBookingAdminEmail::class, function ($mail) use ($admin) {
        return $mail->hasTo($admin->email);
    });
});

test('booking fails if slot is taken during submission (race condition)', function () {
    Mail::fake();

    $client = User::factory()->individual()->create();
    $monday = now()->next('Monday')->format('Y-m-d');

    $this->actingAs($client);

    $component = Volt::test('client.consultations.book')
        ->call('selectSlot', $monday, '10:00')
        ->set('problemSummary', 'I need legal advice regarding a contract dispute.')
        ->call('showConfirm')
        ->assertSet('showConfirmation', true);

    // Another user takes the slot
    Consultation::factory()->approved()->create([
        'booking_date' => $monday,
        'booking_time' => '10:00',
    ]);

    $component->call('submit')
        ->assertHasErrors(['selectedTime'])
        ->assertSet('showConfirmation', false);

    expect(Consultation::where('user_id', $client->id)->exists())->toBeFalse();
});

test('booking fails if user already booked during submission (race condition)', function () {
    Mail::fake();

    $client = User::factory()->individual()->create();
    $monday = now()->next('Monday')->format('Y-m-d');

    $this->actingAs($client);

    $component = Volt::test('client.consultations.book')
        ->call('selectSlot', $monday, '10:00')
        ->set('problemSummary', 'I need legal advice regarding a contract dispute.')
        ->call('showConfirm')
        ->assertSet('showConfirmation', true);

    // User books another slot on same day (from another browser tab)
    Consultation::factory()->pending()->create([
        'user_id' => $client->id,
        'booking_date' => $monday,
        'booking_time' => '11:00',
    ]);

    $component->call('submit')
        ->assertHasErrors(['selectedTime'])
        ->assertSet('showConfirmation', false);

    // Should only have the one booking from the "other tab"
    expect(Consultation::where('user_id', $client->id)->count())->toBe(1);
});
