<?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\Models\WorkingHour;
use App\Notifications\ConsultationCancelled;
use App\Notifications\ConsultationRescheduled;
use App\Services\AvailabilityService;
use Illuminate\Support\Facades\Notification;
use Livewire\Volt\Volt;

// ==========================================
// ACCESS CONTROL TESTS
// ==========================================

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

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

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

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

    $this->actingAs($admin)
        ->get(route('admin.consultations.index'))
        ->assertOk();
});

// ==========================================
// CONSULTATIONS LIST VIEW TESTS
// ==========================================

test('consultations list displays all consultations', function () {
    $admin = User::factory()->admin()->create();
    $client = User::factory()->individual()->create(['full_name' => 'Test Client']);
    Consultation::factory()->approved()->create(['user_id' => $client->id]);

    $this->actingAs($admin);

    Volt::test('admin.consultations.index')
        ->assertSee('Test Client');
});

test('consultations list filters by status', function () {
    $admin = User::factory()->admin()->create();
    $approvedClient = User::factory()->individual()->create(['full_name' => 'Approved Client']);
    $completedClient = User::factory()->individual()->create(['full_name' => 'Completed Client']);

    Consultation::factory()->approved()->create(['user_id' => $approvedClient->id]);
    Consultation::factory()->completed()->create(['user_id' => $completedClient->id]);

    $this->actingAs($admin);

    Volt::test('admin.consultations.index')
        ->set('statusFilter', 'approved')
        ->assertSee('Approved Client')
        ->assertDontSee('Completed Client');
});

test('consultations list filters by consultation type', function () {
    $admin = User::factory()->admin()->create();
    $freeClient = User::factory()->individual()->create(['full_name' => 'Free Client']);
    $paidClient = User::factory()->individual()->create(['full_name' => 'Paid Client']);

    Consultation::factory()->approved()->free()->create(['user_id' => $freeClient->id]);
    Consultation::factory()->approved()->paid()->create(['user_id' => $paidClient->id]);

    $this->actingAs($admin);

    Volt::test('admin.consultations.index')
        ->set('typeFilter', 'free')
        ->assertSee('Free Client')
        ->assertDontSee('Paid Client');
});

test('consultations list filters by payment status', function () {
    $admin = User::factory()->admin()->create();
    $pendingClient = User::factory()->individual()->create(['full_name' => 'Pending Payment']);
    $receivedClient = User::factory()->individual()->create(['full_name' => 'Received Payment']);

    Consultation::factory()->approved()->create([
        'user_id' => $pendingClient->id,
        'consultation_type' => ConsultationType::Paid,
        'payment_status' => PaymentStatus::Pending,
    ]);
    Consultation::factory()->approved()->create([
        'user_id' => $receivedClient->id,
        'consultation_type' => ConsultationType::Paid,
        'payment_status' => PaymentStatus::Received,
    ]);

    $this->actingAs($admin);

    Volt::test('admin.consultations.index')
        ->set('paymentFilter', 'pending')
        ->assertSee('Pending Payment')
        ->assertDontSee('Received Payment');
});

test('consultations list searches by client name', function () {
    $admin = User::factory()->admin()->create();
    $targetUser = User::factory()->individual()->create(['full_name' => 'John Doe']);
    $otherUser = User::factory()->individual()->create(['full_name' => 'Jane Smith']);

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

    $this->actingAs($admin);

    Volt::test('admin.consultations.index')
        ->set('search', 'John')
        ->assertSee('John Doe')
        ->assertDontSee('Jane Smith');
});

test('consultations list filters 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()->approved()->create([
        'user_id' => $oldClient->id,
        'booking_date' => now()->subDays(10),
    ]);
    Consultation::factory()->approved()->create([
        'user_id' => $newClient->id,
        'booking_date' => now()->addDays(5),
    ]);

    $this->actingAs($admin);

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

// ==========================================
// STATUS MANAGEMENT TESTS
// ==========================================

test('admin can mark consultation as completed', function () {
    $admin = User::factory()->admin()->create();
    $consultation = Consultation::factory()->approved()->create();

    $this->actingAs($admin);

    Volt::test('admin.consultations.index')
        ->call('markCompleted', $consultation->id)
        ->assertHasNoErrors();

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

test('cannot mark pending consultation as completed', function () {
    $admin = User::factory()->admin()->create();
    $consultation = Consultation::factory()->pending()->create();

    $this->actingAs($admin);

    Volt::test('admin.consultations.index')
        ->call('markCompleted', $consultation->id);

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

test('admin can mark consultation as no-show', function () {
    $admin = User::factory()->admin()->create();
    $consultation = Consultation::factory()->approved()->create();

    $this->actingAs($admin);

    Volt::test('admin.consultations.index')
        ->call('markNoShow', $consultation->id)
        ->assertHasNoErrors();

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

test('admin can change completed consultation to no-show', function () {
    $admin = User::factory()->admin()->create();
    $consultation = Consultation::factory()->completed()->create();

    $this->actingAs($admin);

    Volt::test('admin.consultations.index')
        ->call('markNoShow', $consultation->id)
        ->assertHasNoErrors();

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

test('admin can change no-show consultation to completed', function () {
    $admin = User::factory()->admin()->create();
    $consultation = Consultation::factory()->noShow()->create();

    $this->actingAs($admin);

    Volt::test('admin.consultations.index')
        ->call('markCompleted', $consultation->id)
        ->assertHasNoErrors();

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

test('admin can cancel approved consultation', function () {
    Notification::fake();

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

    $this->actingAs($admin);

    Volt::test('admin.consultations.index')
        ->call('cancel', $consultation->id)
        ->assertHasNoErrors();

    expect($consultation->fresh()->status)->toBe(ConsultationStatus::Cancelled);
    Notification::assertSentTo($client, ConsultationCancelled::class);
});

test('admin can cancel pending 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.consultations.index')
        ->call('cancel', $consultation->id)
        ->assertHasNoErrors();

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

test('cannot cancel already cancelled consultation', function () {
    Notification::fake();

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

    $this->actingAs($admin);

    Volt::test('admin.consultations.index')
        ->call('cancel', $consultation->id);

    Notification::assertNothingSent();
});

// ==========================================
// PAYMENT TRACKING TESTS
// ==========================================

test('admin can mark payment as received for paid consultation', function () {
    $admin = User::factory()->admin()->create();
    $consultation = Consultation::factory()->approved()->create([
        'consultation_type' => ConsultationType::Paid,
        'payment_amount' => 150.00,
        'payment_status' => PaymentStatus::Pending,
    ]);

    $this->actingAs($admin);

    Volt::test('admin.consultations.index')
        ->call('markPaymentReceived', $consultation->id)
        ->assertHasNoErrors();

    expect($consultation->fresh())
        ->payment_status->toBe(PaymentStatus::Received)
        ->payment_received_at->not->toBeNull();
});

test('cannot mark payment received for free consultation', function () {
    $admin = User::factory()->admin()->create();
    $consultation = Consultation::factory()->approved()->free()->create();

    $this->actingAs($admin);

    Volt::test('admin.consultations.index')
        ->call('markPaymentReceived', $consultation->id);

    expect($consultation->fresh()->payment_status)->toBe(PaymentStatus::NotApplicable);
});

test('cannot mark payment received twice', function () {
    $admin = User::factory()->admin()->create();
    $consultation = Consultation::factory()->approved()->create([
        'consultation_type' => ConsultationType::Paid,
        'payment_status' => PaymentStatus::Received,
        'payment_received_at' => now()->subDay(),
    ]);

    $originalReceivedAt = $consultation->payment_received_at;

    $this->actingAs($admin);

    Volt::test('admin.consultations.index')
        ->call('markPaymentReceived', $consultation->id);

    expect($consultation->fresh()->payment_received_at->timestamp)
        ->toBe($originalReceivedAt->timestamp);
});

// ==========================================
// RESCHEDULE TESTS
// ==========================================

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

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

test('admin can reschedule consultation to available slot', function () {
    Notification::fake();

    $admin = User::factory()->admin()->create();
    $client = User::factory()->individual()->create();
    $consultation = Consultation::factory()->approved()->create([
        'user_id' => $client->id,
        'booking_date' => now()->addDays(3),
        'booking_time' => '10:00:00',
    ]);

    // Create working hours for the new date
    WorkingHour::factory()->create([
        'day_of_week' => now()->addDays(5)->dayOfWeek,
        'is_active' => true,
        'start_time' => '09:00',
        'end_time' => '17:00',
    ]);

    $newDate = now()->addDays(5)->format('Y-m-d');
    $newTime = '14:00';

    $this->actingAs($admin);

    // Mock the availability service
    $this->mock(AvailabilityService::class)
        ->shouldReceive('getAvailableSlots')
        ->andReturn(['14:00', '15:00', '16:00']);

    Volt::test('admin.consultations.show', ['consultation' => $consultation])
        ->set('showRescheduleModal', true)
        ->set('newDate', $newDate)
        ->set('newTime', $newTime)
        ->call('reschedule')
        ->assertHasNoErrors();

    expect($consultation->fresh())
        ->booking_date->format('Y-m-d')->toBe($newDate)
        ->booking_time->toBe($newTime);

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

test('cannot reschedule to unavailable slot', function () {
    $admin = User::factory()->admin()->create();
    $consultation = Consultation::factory()->approved()->create();

    $newDate = now()->addDays(5)->format('Y-m-d');
    $newTime = '14:00';

    $this->actingAs($admin);

    // Mock availability service - slot not available
    $this->mock(AvailabilityService::class)
        ->shouldReceive('getAvailableSlots')
        ->andReturn(['10:00', '11:00']); // 14:00 not in list

    Volt::test('admin.consultations.show', ['consultation' => $consultation])
        ->set('showRescheduleModal', true)
        ->set('newDate', $newDate)
        ->set('newTime', $newTime)
        ->call('reschedule')
        ->assertHasErrors(['newTime']);
});

test('cannot reschedule to past date', function () {
    $admin = User::factory()->admin()->create();
    $consultation = Consultation::factory()->approved()->create();

    $this->actingAs($admin);

    Volt::test('admin.consultations.show', ['consultation' => $consultation])
        ->set('showRescheduleModal', true)
        ->set('newDate', now()->subDay()->format('Y-m-d'))
        ->set('newTime', '10:00')
        ->call('reschedule')
        ->assertHasErrors(['newDate']);
});

// ==========================================
// ADMIN NOTES TESTS
// ==========================================

test('admin can add note to consultation', function () {
    $admin = User::factory()->admin()->create();
    $consultation = Consultation::factory()->approved()->create();

    $this->actingAs($admin);

    Volt::test('admin.consultations.show', ['consultation' => $consultation])
        ->set('newNote', 'Client requested Arabic documents')
        ->call('addNote')
        ->assertHasNoErrors();

    $notes = $consultation->fresh()->admin_notes;
    expect($notes)->toHaveCount(1)
        ->and($notes[0]['text'])->toBe('Client requested Arabic documents')
        ->and($notes[0]['admin_id'])->toBe($admin->id);
});

test('admin can update note', function () {
    $admin = User::factory()->admin()->create();
    $consultation = Consultation::factory()->approved()->create([
        'admin_notes' => [
            ['text' => 'Original note', 'admin_id' => $admin->id, 'created_at' => now()->toISOString()],
        ],
    ]);

    $this->actingAs($admin);

    Volt::test('admin.consultations.show', ['consultation' => $consultation])
        ->call('startEditNote', 0)
        ->set('editingNoteText', 'Updated note')
        ->call('updateNote')
        ->assertHasNoErrors();

    $notes = $consultation->fresh()->admin_notes;
    expect($notes[0]['text'])->toBe('Updated note')
        ->and($notes[0])->toHaveKey('updated_at');
});

test('admin can delete note', function () {
    $admin = User::factory()->admin()->create();
    $consultation = Consultation::factory()->approved()->create([
        'admin_notes' => [
            ['text' => 'Note 1', 'admin_id' => $admin->id, 'created_at' => now()->toISOString()],
            ['text' => 'Note 2', 'admin_id' => $admin->id, 'created_at' => now()->toISOString()],
        ],
    ]);

    $this->actingAs($admin);

    Volt::test('admin.consultations.show', ['consultation' => $consultation])
        ->call('deleteNote', 0)
        ->assertHasNoErrors();

    $notes = $consultation->fresh()->admin_notes;
    expect($notes)->toHaveCount(1)
        ->and($notes[0]['text'])->toBe('Note 2');
});

// ==========================================
// AUDIT LOG TESTS
// ==========================================

test('audit log entry created on status change to completed', function () {
    $admin = User::factory()->admin()->create();
    $consultation = Consultation::factory()->approved()->create();

    $this->actingAs($admin);

    Volt::test('admin.consultations.index')
        ->call('markCompleted', $consultation->id);

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

test('audit log entry created on payment received', function () {
    $admin = User::factory()->admin()->create();
    $consultation = Consultation::factory()->approved()->create([
        'consultation_type' => ConsultationType::Paid,
        'payment_status' => PaymentStatus::Pending,
    ]);

    $this->actingAs($admin);

    Volt::test('admin.consultations.index')
        ->call('markPaymentReceived', $consultation->id);

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

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

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

    $newDate = now()->addDays(5)->format('Y-m-d');

    $this->actingAs($admin);

    $this->mock(AvailabilityService::class)
        ->shouldReceive('getAvailableSlots')
        ->andReturn(['14:00']);

    Volt::test('admin.consultations.show', ['consultation' => $consultation])
        ->set('showRescheduleModal', true)
        ->set('newDate', $newDate)
        ->set('newTime', '14:00')
        ->call('reschedule');

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

// ==========================================
// CLIENT HISTORY TESTS
// ==========================================

test('admin can access client consultation history', function () {
    $admin = User::factory()->admin()->create();
    $client = User::factory()->individual()->create();

    $this->actingAs($admin)
        ->get(route('admin.clients.consultation-history', $client))
        ->assertOk();
});

test('client consultation history displays consultations', function () {
    $admin = User::factory()->admin()->create();
    $client = User::factory()->individual()->create();

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

    $this->actingAs($admin);

    Volt::test('admin.clients.consultation-history', ['user' => $client])
        ->assertOk();
});

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

    Consultation::factory()->completed()->count(2)->create(['user_id' => $client->id]);
    Consultation::factory()->cancelled()->create(['user_id' => $client->id]);
    Consultation::factory()->noShow()->create(['user_id' => $client->id]);

    $this->actingAs($admin);

    Volt::test('admin.clients.consultation-history', ['user' => $client])
        ->assertSee('4') // total
        ->assertSee('2'); // completed
});

// ==========================================
// BILINGUAL TESTS
// ==========================================

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

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

    $this->actingAs($admin);

    Volt::test('admin.consultations.index')
        ->call('cancel', $consultation->id);

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