<?php

use App\Models\Consultation;
use App\Models\User;
use App\Services\AnalyticsService;
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 analytics charts section', function () {
    $this->actingAs($this->admin)
        ->get(route('admin.dashboard'))
        ->assertSuccessful()
        ->assertSee(__('admin_metrics.analytics_charts'))
        ->assertSee(__('admin_metrics.monthly_trends'));
});

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

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

// ===========================================
// AnalyticsService Unit Tests
// ===========================================

test('analytics service returns correct monthly client counts', function () {
    // Create clients across different months
    User::factory()->individual()->create([
        'created_at' => now()->subMonths(2)->startOfMonth()->addDays(5),
    ]);
    User::factory()->count(3)->individual()->create([
        'created_at' => now()->subMonth()->startOfMonth()->addDays(5),
    ]);
    User::factory()->count(2)->company()->create([
        'created_at' => now()->startOfMonth()->addDays(5),
    ]);

    $service = new AnalyticsService;
    $data = $service->getMonthlyNewClients(now()->subMonths(2)->startOfMonth(), 3);

    expect($data)->toBe([1, 3, 2]);
});

test('analytics service returns correct monthly consultation counts', function () {
    Consultation::factory()->count(2)->create([
        'booking_date' => now()->subMonths(2)->startOfMonth()->addDays(5),
    ]);
    Consultation::factory()->count(4)->create([
        'booking_date' => now()->subMonth()->startOfMonth()->addDays(5),
    ]);
    Consultation::factory()->count(3)->create([
        'booking_date' => now()->startOfMonth()->addDays(5),
    ]);

    $service = new AnalyticsService;
    $data = $service->getMonthlyConsultations(now()->subMonths(2)->startOfMonth(), 3);

    expect($data)->toBe([2, 4, 3]);
});

test('consultation breakdown calculates free vs paid correctly', function () {
    Consultation::factory()->count(5)->free()->create([
        'booking_date' => now()->subMonth(),
    ]);
    Consultation::factory()->count(3)->paid()->create([
        'booking_date' => now()->subMonth(),
    ]);

    $service = new AnalyticsService;
    $breakdown = $service->getConsultationTypeBreakdown(now()->subYear()->startOfMonth(), 12);

    expect($breakdown['free'])->toBe(5)
        ->and($breakdown['paid'])->toBe(3);
});

test('no-show rate calculates correctly', function () {
    // Create 8 completed, 2 no-shows = 20% rate
    Consultation::factory()->count(8)->completed()->create([
        'booking_date' => now()->startOfMonth()->addDays(5),
    ]);
    Consultation::factory()->count(2)->noShow()->create([
        'booking_date' => now()->startOfMonth()->addDays(5),
    ]);

    $service = new AnalyticsService;
    $rates = $service->getMonthlyNoShowRates(now()->startOfMonth(), 1);

    expect($rates[0])->toBe(20.0);
});

test('no-show rate returns zero when no consultations exist', function () {
    $service = new AnalyticsService;
    $rates = $service->getMonthlyNoShowRates(now()->startOfMonth(), 1);

    expect($rates[0])->toBe(0);
});

test('no-show rate handles zero completed consultations', function () {
    // Only create pending consultations (not completed or no-show)
    Consultation::factory()->count(5)->pending()->create([
        'booking_date' => now()->startOfMonth()->addDays(5),
    ]);

    $service = new AnalyticsService;
    $rates = $service->getMonthlyNoShowRates(now()->startOfMonth(), 1);

    expect($rates[0])->toBe(0);
});

test('month labels are generated correctly', function () {
    $service = new AnalyticsService;
    $labels = $service->getMonthLabels(now()->startOfMonth(), 3);

    expect($labels)->toHaveCount(3)
        ->and($labels[0])->toBe(now()->startOfMonth()->translatedFormat('M Y'))
        ->and($labels[1])->toBe(now()->addMonth()->translatedFormat('M Y'))
        ->and($labels[2])->toBe(now()->addMonths(2)->translatedFormat('M Y'));
});

// ===========================================
// Dashboard Component Chart Data Tests
// ===========================================

test('dashboard provides chart data', function () {
    $this->actingAs($this->admin);

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

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

    expect($chartData)->toHaveKeys(['labels', 'newClients', 'consultations', 'consultationBreakdown', 'noShowRates'])
        ->and($chartData['consultationBreakdown'])->toHaveKeys(['free', 'paid']);
});

test('chart data defaults to 6 months', function () {
    $this->actingAs($this->admin);

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

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

    expect($chartData['labels'])->toHaveCount(6)
        ->and($chartData['newClients'])->toHaveCount(6)
        ->and($chartData['consultations'])->toHaveCount(6)
        ->and($chartData['noShowRates'])->toHaveCount(6);
});

test('date range selector changes chart period to 12 months', function () {
    $this->actingAs($this->admin);

    $component = Volt::test('admin.dashboard')
        ->assertSet('chartPeriod', '6m')
        ->set('chartPeriod', '12m')
        ->assertSet('chartPeriod', '12m');

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

    expect($chartData['labels'])->toHaveCount(12)
        ->and($chartData['newClients'])->toHaveCount(12)
        ->and($chartData['consultations'])->toHaveCount(12)
        ->and($chartData['noShowRates'])->toHaveCount(12);
});

test('custom date range can be set', function () {
    $this->actingAs($this->admin);

    $start = now()->subMonths(3)->format('Y-m');
    $end = now()->format('Y-m');

    $component = Volt::test('admin.dashboard')
        ->set('customStartMonth', $start)
        ->set('customEndMonth', $end)
        ->call('setCustomRange')
        ->assertSet('chartPeriod', 'custom');

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

    expect($chartData['labels'])->toHaveCount(4); // 4 months inclusive
});

test('chart handles empty data gracefully', function () {
    $this->actingAs($this->admin);

    // No clients or consultations created
    $component = Volt::test('admin.dashboard');

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

    // Should have all zeros but not error
    expect(array_sum($chartData['newClients']))->toBe(0)
        ->and(array_sum($chartData['consultations']))->toBe(0)
        ->and($chartData['consultationBreakdown']['free'])->toBe(0)
        ->and($chartData['consultationBreakdown']['paid'])->toBe(0)
        ->and(array_sum($chartData['noShowRates']))->toBe(0);
});

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

test('dashboard displays chart section with date range buttons', function () {
    $this->actingAs($this->admin)
        ->get(route('admin.dashboard'))
        ->assertSee(__('admin_metrics.last_6_months'))
        ->assertSee(__('admin_metrics.last_12_months'))
        ->assertSee(__('admin_metrics.apply'));
});

test('dashboard displays all chart cards', function () {
    $this->actingAs($this->admin)
        ->get(route('admin.dashboard'))
        ->assertSee(__('admin_metrics.monthly_trends'))
        ->assertSee(__('admin_metrics.consultation_breakdown'))
        ->assertSee(__('admin_metrics.noshow_rate_trend'));
});

test('empty state message shown when no data', function () {
    $this->actingAs($this->admin)
        ->get(route('admin.dashboard'))
        ->assertSee(__('admin_metrics.no_data_available'));
});

// ===========================================
// Data Accuracy Tests
// ===========================================

test('chart data excludes admin users from client counts', function () {
    // Create admin users (should not be counted)
    User::factory()->count(2)->admin()->create([
        'created_at' => now()->startOfMonth()->addDays(5),
    ]);

    // Create individual clients (should be counted)
    User::factory()->count(3)->individual()->create([
        'created_at' => now()->startOfMonth()->addDays(5),
    ]);

    $service = new AnalyticsService;
    $data = $service->getMonthlyNewClients(now()->startOfMonth(), 1);

    expect($data[0])->toBe(3);
});

test('chart data correctly filters by date range', function () {
    // Create consultations outside the range
    Consultation::factory()->count(5)->create([
        'booking_date' => now()->subYears(2),
    ]);

    // Create consultations inside the range
    Consultation::factory()->count(3)->create([
        'booking_date' => now()->subMonth()->startOfMonth()->addDays(5),
    ]);

    $service = new AnalyticsService;
    $data = $service->getMonthlyConsultations(now()->subMonths(2)->startOfMonth(), 3);

    // Only the 3 consultations in range should be counted
    expect(array_sum($data))->toBe(3);
});
