<?php

use App\Enums\ConsultationStatus;
use App\Enums\ConsultationType;
use App\Enums\PaymentStatus;
use App\Models\AdminLog;
use App\Models\Consultation;
use App\Models\User;
use App\Notifications\BookingApproved;
use App\Notifications\BookingRejected;
use Illuminate\Support\Facades\Notification;
use Livewire\Volt\Volt;

test('guest cannot access pending bookings page', function () {
    $this->get(route('admin.bookings.pending'))
        ->assertRedirect(route('login'));
});

test('client cannot access pending bookings page', function () {
    $client = User::factory()->individual()->create();

    $this->actingAs($client)
        ->get(route('admin.bookings.pending'))
        ->assertForbidden();
});

test('admin can access pending bookings page', function () {
    $admin = User::factory()->admin()->create();

    $this->actingAs($admin)
        ->get(route('admin.bookings.pending'))
        ->assertOk();
});

test('pending bookings list displays pending consultations', function () {
    $admin = User::factory()->admin()->create();
    $client = User::factory()->individual()->create();
    $consultation = Consultation::factory()->pending()->create([
        'user_id' => $client->id,
    ]);

    $this->actingAs($admin);

    Volt::test('admin.bookings.pending')
        ->assertSee($client->full_name);
});

test('pending bookings list does not show non-pending consultations', function () {
    $admin = User::factory()->admin()->create();
    $client = User::factory()->individual()->create();

    Consultation::factory()->approved()->create([
        'user_id' => $client->id,
    ]);

    $this->actingAs($admin);

    Volt::test('admin.bookings.pending')
        ->assertDontSee($client->full_name);
});

test('admin can filter bookings by date range', function () {
    $admin = User::factory()->admin()->create();
    $oldClient = User::factory()->individual()->create(['full_name' => 'Old Client']);
    $newClient = User::factory()->individual()->create(['full_name' => 'New Client']);

    Consultation::factory()->pending()->create([
        'user_id' => $oldClient->id,
        'booking_date' => now()->subDays(10),
    ]);
    Consultation::factory()->pending()->create([
        'user_id' => $newClient->id,
        'booking_date' => now()->addDays(5),
    ]);

    $this->actingAs($admin);

    Volt::test('admin.bookings.pending')
        ->set('dateFrom', now()->format('Y-m-d'))
        ->assertSee('New Client')
        ->assertDontSee('Old Client');
});

test('admin can access booking review page', function () {
    $admin = User::factory()->admin()->create();
    $consultation = Consultation::factory()->pending()->create();

    $this->actingAs($admin)
        ->get(route('admin.bookings.review', $consultation))
        ->assertOk();
});

test('admin can approve booking as free consultation', function () {
    Notification::fake();

    $admin = User::factory()->admin()->create();
    $client = User::factory()->individual()->create();
    $consultation = Consultation::factory()->pending()->create([
        'user_id' => $client->id,
    ]);

    $this->actingAs($admin);

    Volt::test('admin.bookings.review', ['consultation' => $consultation])
        ->set('consultationType', 'free')
        ->call('approve')
        ->assertHasNoErrors()
        ->assertRedirect(route('admin.bookings.pending'));

    expect($consultation->fresh())
        ->status->toBe(ConsultationStatus::Approved)
        ->consultation_type->toBe(ConsultationType::Free)
        ->payment_status->toBe(PaymentStatus::NotApplicable);

    Notification::assertSentTo($client, BookingApproved::class);
});

test('admin can approve booking as paid consultation with amount', function () {
    Notification::fake();

    $admin = User::factory()->admin()->create();
    $client = User::factory()->individual()->create();
    $consultation = Consultation::factory()->pending()->create([
        'user_id' => $client->id,
    ]);

    $this->actingAs($admin);

    Volt::test('admin.bookings.review', ['consultation' => $consultation])
        ->set('consultationType', 'paid')
        ->set('paymentAmount', '150.00')
        ->set('paymentInstructions', 'Bank transfer to account XYZ')
        ->call('approve')
        ->assertHasNoErrors();

    expect($consultation->fresh())
        ->status->toBe(ConsultationStatus::Approved)
        ->consultation_type->toBe(ConsultationType::Paid)
        ->payment_amount->toBe('150.00')
        ->payment_status->toBe(PaymentStatus::Pending);
});

test('paid consultation requires payment amount', function () {
    $admin = User::factory()->admin()->create();
    $consultation = Consultation::factory()->pending()->create();

    $this->actingAs($admin);

    Volt::test('admin.bookings.review', ['consultation' => $consultation])
        ->set('consultationType', 'paid')
        ->set('paymentAmount', null)
        ->call('approve')
        ->assertHasErrors(['paymentAmount']);
});

test('admin can reject booking with reason', function () {
    Notification::fake();

    $admin = User::factory()->admin()->create();
    $client = User::factory()->individual()->create();
    $consultation = Consultation::factory()->pending()->create([
        'user_id' => $client->id,
    ]);

    $this->actingAs($admin);

    Volt::test('admin.bookings.review', ['consultation' => $consultation])
        ->set('rejectionReason', 'Schedule conflict')
        ->call('reject')
        ->assertHasNoErrors()
        ->assertRedirect(route('admin.bookings.pending'));

    expect($consultation->fresh())->status->toBe(ConsultationStatus::Rejected);

    Notification::assertSentTo($client, BookingRejected::class);
});

test('admin can reject booking without reason', function () {
    Notification::fake();

    $admin = User::factory()->admin()->create();
    $client = User::factory()->individual()->create();
    $consultation = Consultation::factory()->pending()->create([
        'user_id' => $client->id,
    ]);

    $this->actingAs($admin);

    Volt::test('admin.bookings.review', ['consultation' => $consultation])
        ->call('reject')
        ->assertHasNoErrors();

    expect($consultation->fresh())->status->toBe(ConsultationStatus::Rejected);
});

test('quick approve from list works', function () {
    Notification::fake();

    $admin = User::factory()->admin()->create();
    $client = User::factory()->individual()->create();
    $consultation = Consultation::factory()->pending()->create([
        'user_id' => $client->id,
    ]);

    $this->actingAs($admin);

    Volt::test('admin.bookings.pending')
        ->call('openApproveModal', $consultation->id)
        ->assertSet('showApproveModal', true)
        ->assertSet('approvingBookingId', $consultation->id)
        ->set('consultationType', 'free')
        ->call('quickApprove')
        ->assertHasNoErrors();

    expect($consultation->fresh())
        ->status->toBe(ConsultationStatus::Approved)
        ->consultation_type->toBe(ConsultationType::Free);

    Notification::assertSentTo($client, BookingApproved::class);
});

test('quick reject from list works', function () {
    Notification::fake();

    $admin = User::factory()->admin()->create();
    $client = User::factory()->individual()->create();
    $consultation = Consultation::factory()->pending()->create([
        'user_id' => $client->id,
    ]);

    $this->actingAs($admin);

    Volt::test('admin.bookings.pending')
        ->call('quickReject', $consultation->id)
        ->assertHasNoErrors();

    expect($consultation->fresh())->status->toBe(ConsultationStatus::Rejected);

    Notification::assertSentTo($client, BookingRejected::class);
});

test('audit log entry created on approval', function () {
    Notification::fake();

    $admin = User::factory()->admin()->create();
    $client = User::factory()->individual()->create();
    $consultation = Consultation::factory()->pending()->create([
        'user_id' => $client->id,
    ]);

    $this->actingAs($admin);

    Volt::test('admin.bookings.review', ['consultation' => $consultation])
        ->set('consultationType', 'free')
        ->call('approve');

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

test('audit log entry created on rejection', function () {
    Notification::fake();

    $admin = User::factory()->admin()->create();
    $client = User::factory()->individual()->create();
    $consultation = Consultation::factory()->pending()->create([
        'user_id' => $client->id,
    ]);

    $this->actingAs($admin);

    Volt::test('admin.bookings.review', ['consultation' => $consultation])
        ->set('rejectionReason', 'Not available')
        ->call('reject');

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

test('cannot approve already approved booking', function () {
    Notification::fake();

    $admin = User::factory()->admin()->create();
    $consultation = Consultation::factory()->approved()->create();

    $this->actingAs($admin);

    // Ensure status doesn't change
    Volt::test('admin.bookings.review', ['consultation' => $consultation])
        ->call('approve');

    // Verify consultation status is still approved (not changed)
    expect($consultation->fresh()->status)->toBe(ConsultationStatus::Approved);

    // Verify no duplicate notification was sent
    Notification::assertNothingSent();
});

test('cannot reject already rejected booking', function () {
    Notification::fake();

    $admin = User::factory()->admin()->create();
    $consultation = Consultation::factory()->create([
        'status' => ConsultationStatus::Rejected,
    ]);

    $this->actingAs($admin);

    // Ensure status doesn't change
    Volt::test('admin.bookings.review', ['consultation' => $consultation])
        ->call('reject');

    // Verify consultation status is still rejected (not changed)
    expect($consultation->fresh()->status)->toBe(ConsultationStatus::Rejected);

    // Verify no notification was sent
    Notification::assertNothingSent();
});

test('booking details view shows client consultation history', function () {
    $admin = User::factory()->admin()->create();
    $client = User::factory()->individual()->create();

    // Create past consultations
    Consultation::factory()->completed()->create([
        'user_id' => $client->id,
        'booking_date' => now()->subMonth(),
    ]);

    // Create current pending consultation
    $consultation = Consultation::factory()->pending()->create([
        'user_id' => $client->id,
    ]);

    $this->actingAs($admin);

    Volt::test('admin.bookings.review', ['consultation' => $consultation])
        ->assertOk();
});

test('notification sent in client preferred language arabic', function () {
    Notification::fake();

    $admin = User::factory()->admin()->create();
    $arabicClient = User::factory()->individual()->create([
        'preferred_language' => 'ar',
    ]);
    $consultation = Consultation::factory()->pending()->create([
        'user_id' => $arabicClient->id,
    ]);

    $this->actingAs($admin);

    Volt::test('admin.bookings.review', ['consultation' => $consultation])
        ->set('consultationType', 'free')
        ->call('approve');

    Notification::assertSentTo($arabicClient, BookingApproved::class, function ($notification) {
        return $notification->consultation->user->preferred_language === 'ar';
    });
});

test('notification sent in client preferred language english', function () {
    Notification::fake();

    $admin = User::factory()->admin()->create();
    $englishClient = User::factory()->individual()->create([
        'preferred_language' => 'en',
    ]);
    $consultation = Consultation::factory()->pending()->create([
        'user_id' => $englishClient->id,
    ]);

    $this->actingAs($admin);

    Volt::test('admin.bookings.review', ['consultation' => $consultation])
        ->set('consultationType', 'free')
        ->call('approve');

    Notification::assertSentTo($englishClient, BookingApproved::class, function ($notification) {
        return $notification->consultation->user->preferred_language === 'en';
    });
});
