<?php

use App\Enums\ConsultationStatus;
use App\Enums\ConsultationType;
use App\Enums\TimelineStatus;
use App\Enums\UserStatus;
use App\Models\Consultation;
use App\Models\Post;
use App\Models\Timeline;
use App\Models\TimelineUpdate;
use App\Models\User;
use Illuminate\Support\Facades\Cache;
use Livewire\Volt\Volt;

beforeEach(function () {
    $this->admin = User::factory()->admin()->create();
    Cache::flush();
});

// ===========================================
// Access Control Tests
// ===========================================

test('admin can view dashboard', function () {
    $this->actingAs($this->admin)
        ->get(route('admin.dashboard'))
        ->assertSuccessful()
        ->assertSee(__('admin_metrics.title'));
});

test('non-admin cannot access dashboard', function () {
    $client = User::factory()->individual()->create();

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

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

// ===========================================
// User Metrics Tests
// ===========================================

test('dashboard displays correct user metrics', function () {
    User::factory()->count(5)->individual()->create(['status' => UserStatus::Active]);
    User::factory()->count(3)->company()->create(['status' => UserStatus::Active]);
    User::factory()->count(2)->individual()->create(['status' => UserStatus::Deactivated]);

    $this->actingAs($this->admin);

    $component = Volt::test('admin.dashboard');

    $userMetrics = $component->viewData('userMetrics');

    expect($userMetrics['total_active'])->toBe(8)
        ->and($userMetrics['individual'])->toBe(5)
        ->and($userMetrics['company'])->toBe(3)
        ->and($userMetrics['deactivated'])->toBe(2);
});

test('dashboard counts new clients this month correctly', function () {
    // Create clients this month
    User::factory()->count(3)->individual()->create([
        'status' => UserStatus::Active,
        'created_at' => now(),
    ]);

    // Create clients from last month
    User::factory()->count(2)->individual()->create([
        'status' => UserStatus::Active,
        'created_at' => now()->subMonth(),
    ]);

    $this->actingAs($this->admin);

    $component = Volt::test('admin.dashboard');

    $userMetrics = $component->viewData('userMetrics');

    expect($userMetrics['new_this_month'])->toBe(3);
});

test('user metrics excludes admin users from counts', function () {
    User::factory()->admin()->create();
    User::factory()->count(2)->individual()->create(['status' => UserStatus::Active]);

    $this->actingAs($this->admin);

    $component = Volt::test('admin.dashboard');

    $userMetrics = $component->viewData('userMetrics');

    // Should only count the 2 individual clients, not the admin
    expect($userMetrics['total_active'])->toBe(2);
});

// ===========================================
// Booking Metrics Tests
// ===========================================

test('dashboard displays correct booking metrics', function () {
    // Create 3 pending consultations
    Consultation::factory()->count(3)->create(['status' => ConsultationStatus::Pending]);

    // Create 2 approved consultations for today
    Consultation::factory()->count(2)->create([
        'status' => ConsultationStatus::Approved,
        'booking_date' => today(),
    ]);

    // Create 5 free consultations (completed status to avoid counting as pending)
    Consultation::factory()->count(5)->create([
        'consultation_type' => ConsultationType::Free,
        'status' => ConsultationStatus::Completed,
    ]);

    // Create 4 paid consultations (completed status to avoid counting as pending)
    Consultation::factory()->count(4)->create([
        'consultation_type' => ConsultationType::Paid,
        'status' => ConsultationStatus::Completed,
    ]);

    $this->actingAs($this->admin);

    $component = Volt::test('admin.dashboard');

    $bookingMetrics = $component->viewData('bookingMetrics');

    // 3 pending + 2 approved today (not pending) = 3 pending
    // 2 approved for today
    // 5 free + some from the other consultations
    // 4 paid + some from the other consultations
    expect($bookingMetrics['pending'])->toBe(3)
        ->and($bookingMetrics['today'])->toBe(2);
});

test('no-show rate calculates correctly', function () {
    // Create 10 completed consultations
    Consultation::factory()->count(8)->create(['status' => ConsultationStatus::Completed]);
    // Create 2 no-shows = 20% rate
    Consultation::factory()->count(2)->create(['status' => ConsultationStatus::NoShow]);

    $this->actingAs($this->admin);

    $component = Volt::test('admin.dashboard');

    $bookingMetrics = $component->viewData('bookingMetrics');

    expect($bookingMetrics['no_show_rate'])->toBe(20.0);
});

test('no-show rate handles division by zero', function () {
    // No completed or no-show consultations
    Consultation::factory()->create(['status' => ConsultationStatus::Pending]);

    $this->actingAs($this->admin);

    $component = Volt::test('admin.dashboard');

    $bookingMetrics = $component->viewData('bookingMetrics');

    expect($bookingMetrics['no_show_rate'])->toBe(0);
});

test('this week consultations counts correctly', function () {
    // Create consultations this week
    Consultation::factory()->count(3)->create([
        'booking_date' => now()->startOfWeek()->addDays(2),
        'status' => ConsultationStatus::Approved,
    ]);

    // Create consultations outside this week
    Consultation::factory()->count(2)->create([
        'booking_date' => now()->subWeeks(2),
        'status' => ConsultationStatus::Approved,
    ]);

    $this->actingAs($this->admin);

    $component = Volt::test('admin.dashboard');

    $bookingMetrics = $component->viewData('bookingMetrics');

    expect($bookingMetrics['this_week'])->toBe(3);
});

test('this month consultations counts correctly', function () {
    // Create consultations this month
    Consultation::factory()->count(4)->create([
        'booking_date' => now()->startOfMonth()->addDays(5),
    ]);

    // Create consultations last month
    Consultation::factory()->count(2)->create([
        'booking_date' => now()->subMonth(),
    ]);

    $this->actingAs($this->admin);

    $component = Volt::test('admin.dashboard');

    $bookingMetrics = $component->viewData('bookingMetrics');

    expect($bookingMetrics['this_month'])->toBe(4);
});

// ===========================================
// Timeline Metrics Tests
// ===========================================

test('dashboard displays correct timeline metrics', function () {
    Timeline::factory()->count(5)->create(['status' => TimelineStatus::Active]);
    Timeline::factory()->count(3)->create(['status' => TimelineStatus::Archived]);

    $this->actingAs($this->admin);

    $component = Volt::test('admin.dashboard');

    $timelineMetrics = $component->viewData('timelineMetrics');

    expect($timelineMetrics['active'])->toBe(5)
        ->and($timelineMetrics['archived'])->toBe(3);
});

test('timeline updates this week counts correctly', function () {
    $timeline = Timeline::factory()->create();

    // Create updates this week
    TimelineUpdate::factory()->count(4)->create([
        'timeline_id' => $timeline->id,
        'created_at' => now()->subDays(3),
    ]);

    // Create updates older than a week
    TimelineUpdate::factory()->count(2)->create([
        'timeline_id' => $timeline->id,
        'created_at' => now()->subWeeks(2),
    ]);

    $this->actingAs($this->admin);

    $component = Volt::test('admin.dashboard');

    $timelineMetrics = $component->viewData('timelineMetrics');

    expect($timelineMetrics['updates_this_week'])->toBe(4);
});

// ===========================================
// Post Metrics Tests
// ===========================================

test('dashboard displays correct post metrics', function () {
    Post::factory()->count(5)->published()->create();
    Post::factory()->count(3)->draft()->create();

    $this->actingAs($this->admin);

    $component = Volt::test('admin.dashboard');

    $postMetrics = $component->viewData('postMetrics');

    expect($postMetrics['total_published'])->toBe(5);
});

test('posts published this month counts correctly', function () {
    // Create posts published this month
    Post::factory()->count(3)->published()->create([
        'published_at' => now(),
    ]);

    // Create posts published last month
    Post::factory()->count(2)->published()->create([
        'published_at' => now()->subMonth(),
    ]);

    $this->actingAs($this->admin);

    $component = Volt::test('admin.dashboard');

    $postMetrics = $component->viewData('postMetrics');

    expect($postMetrics['this_month'])->toBe(3);
});

// ===========================================
// Empty State Tests
// ===========================================

test('dashboard handles empty database gracefully', function () {
    $this->actingAs($this->admin)
        ->get(route('admin.dashboard'))
        ->assertSuccessful()
        ->assertSee('0');
});

test('all metrics show zero when no data exists', function () {
    $this->actingAs($this->admin);

    $component = Volt::test('admin.dashboard');

    $userMetrics = $component->viewData('userMetrics');
    $bookingMetrics = $component->viewData('bookingMetrics');
    $timelineMetrics = $component->viewData('timelineMetrics');
    $postMetrics = $component->viewData('postMetrics');

    expect($userMetrics['total_active'])->toBe(0)
        ->and($userMetrics['individual'])->toBe(0)
        ->and($userMetrics['company'])->toBe(0)
        ->and($userMetrics['deactivated'])->toBe(0)
        ->and($userMetrics['new_this_month'])->toBe(0)
        ->and($bookingMetrics['pending'])->toBe(0)
        ->and($bookingMetrics['today'])->toBe(0)
        ->and($bookingMetrics['this_week'])->toBe(0)
        ->and($bookingMetrics['this_month'])->toBe(0)
        ->and($bookingMetrics['free'])->toBe(0)
        ->and($bookingMetrics['paid'])->toBe(0)
        ->and($bookingMetrics['no_show_rate'])->toBe(0)
        ->and($timelineMetrics['active'])->toBe(0)
        ->and($timelineMetrics['archived'])->toBe(0)
        ->and($timelineMetrics['updates_this_week'])->toBe(0)
        ->and($postMetrics['total_published'])->toBe(0)
        ->and($postMetrics['this_month'])->toBe(0);
});

// ===========================================
// Cache Tests
// ===========================================

test('metrics are cached for 5 minutes', function () {
    $this->actingAs($this->admin);

    // First load to populate cache
    Volt::test('admin.dashboard');

    // Verify cache keys exist
    expect(Cache::has('admin.metrics.users'))->toBeTrue()
        ->and(Cache::has('admin.metrics.bookings'))->toBeTrue()
        ->and(Cache::has('admin.metrics.timelines'))->toBeTrue()
        ->and(Cache::has('admin.metrics.posts'))->toBeTrue();
});

test('cached metrics persist after data changes', function () {
    $this->actingAs($this->admin);

    // First load to populate cache
    $component = Volt::test('admin.dashboard');
    $initialCount = $component->viewData('userMetrics')['total_active'];

    // Add new users
    User::factory()->count(5)->individual()->create(['status' => UserStatus::Active]);

    // Reload component - should still show cached value
    $component = Volt::test('admin.dashboard');
    $cachedCount = $component->viewData('userMetrics')['total_active'];

    expect($cachedCount)->toBe($initialCount);
});

// ===========================================
// UI Element Tests
// ===========================================

test('dashboard displays all metric cards', function () {
    $this->actingAs($this->admin)
        ->get(route('admin.dashboard'))
        ->assertSee(__('admin_metrics.clients'))
        ->assertSee(__('admin_metrics.consultations'))
        ->assertSee(__('admin_metrics.timelines'))
        ->assertSee(__('admin_metrics.posts'));
});

test('pending requests badge is displayed', function () {
    Consultation::factory()->count(5)->create(['status' => ConsultationStatus::Pending]);

    $this->actingAs($this->admin)
        ->get(route('admin.dashboard'))
        ->assertSee(__('admin_metrics.pending_requests'));
});
