<?php

use App\Models\Consultation;
use App\Models\Post;
use App\Models\Timeline;
use App\Models\TimelineUpdate;
use App\Models\User;
use App\Services\MonthlyReportService;
use Livewire\Volt\Volt;

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

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

test('admin can access monthly report page', function () {
    $this->actingAs($this->admin)
        ->get(route('admin.reports.monthly'))
        ->assertOk()
        ->assertSee(__('report.monthly_report'));
});

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

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

test('unauthenticated user cannot access monthly report page', function () {
    $this->get(route('admin.reports.monthly'))
        ->assertRedirect(route('login'));
});

// ===========================================
// Component Tests
// ===========================================

test('monthly report component mounts with previous month as default', function () {
    $this->actingAs($this->admin);

    $previousMonth = now()->subMonth();

    Volt::test('admin.reports.monthly-report')
        ->assertSet('selectedPeriod', $previousMonth->format('Y-m'));
});

test('available months shows only last 12 months', function () {
    $this->actingAs($this->admin);

    $component = Volt::test('admin.reports.monthly-report');

    $availableMonths = $component->get('availableMonths');

    expect(count($availableMonths))->toBe(12);
});

test('available months does not include current month', function () {
    $this->actingAs($this->admin);

    $component = Volt::test('admin.reports.monthly-report');

    $availableMonths = $component->get('availableMonths');
    $currentMonth = now()->format('Y-m');

    $values = array_column($availableMonths, 'value');

    expect($values)->not->toContain($currentMonth);
});

test('available months includes previous month', function () {
    $this->actingAs($this->admin);

    $component = Volt::test('admin.reports.monthly-report');

    $availableMonths = $component->get('availableMonths');
    $previousMonth = now()->subMonth()->format('Y-m');

    $values = array_column($availableMonths, 'value');

    expect($values)->toContain($previousMonth);
});

// ===========================================
// PDF Generation Tests
// ===========================================

test('monthly report generates valid PDF', function () {
    $this->actingAs($this->admin);

    // Create test data for the month
    $targetMonth = now()->subMonth();
    User::factory()->count(5)->individual()->create([
        'created_at' => $targetMonth,
    ]);
    Consultation::factory()->count(10)->create([
        'booking_date' => $targetMonth,
    ]);

    Volt::test('admin.reports.monthly-report')
        ->set('selectedPeriod', $targetMonth->format('Y-m'))
        ->call('generate')
        ->assertFileDownloaded("monthly-report-{$targetMonth->year}-{$targetMonth->month}.pdf");
});

test('report handles month with no data gracefully', function () {
    $this->actingAs($this->admin);

    // Generate for a month with no data (far in the past)
    $emptyMonth = now()->subMonths(10);

    Volt::test('admin.reports.monthly-report')
        ->set('selectedPeriod', $emptyMonth->format('Y-m'))
        ->call('generate')
        ->assertFileDownloaded();
});

// ===========================================
// Service Tests - User Statistics
// ===========================================

test('user statistics are accurate for selected month', function () {
    $targetMonth = now()->subMonth();
    $startDate = $targetMonth->copy()->startOfMonth();
    $endDate = $targetMonth->copy()->endOfMonth();

    // Create 3 users in target month
    User::factory()->count(3)->individual()->create([
        'created_at' => $targetMonth,
    ]);

    // Create 2 users in different month (should not be counted as new)
    User::factory()->count(2)->individual()->create([
        'created_at' => now()->subMonths(3),
    ]);

    $service = new MonthlyReportService;
    $stats = $service->getUserStats($startDate, $endDate);

    expect($stats['new_clients'])->toBe(3);
});

test('user statistics count individual and company clients separately', function () {
    $targetMonth = now()->subMonth();
    $startDate = $targetMonth->copy()->startOfMonth();
    $endDate = $targetMonth->copy()->endOfMonth();

    User::factory()->count(4)->individual()->create([
        'created_at' => $targetMonth->copy()->subMonth(),
    ]);
    User::factory()->count(2)->company()->create([
        'created_at' => $targetMonth->copy()->subMonth(),
    ]);

    $service = new MonthlyReportService;
    $stats = $service->getUserStats($startDate, $endDate);

    expect($stats['individual'])->toBe(4);
    expect($stats['company'])->toBe(2);
    expect($stats['total_active'])->toBe(6);
});

// ===========================================
// Service Tests - Consultation Statistics
// ===========================================

test('consultation statistics calculate totals correctly', function () {
    $targetMonth = now()->subMonth();
    $startDate = $targetMonth->copy()->startOfMonth();
    $endDate = $targetMonth->copy()->endOfMonth();

    Consultation::factory()->count(5)->completed()->create([
        'booking_date' => $targetMonth,
    ]);
    Consultation::factory()->count(3)->pending()->create([
        'booking_date' => $targetMonth,
    ]);
    Consultation::factory()->count(2)->cancelled()->create([
        'booking_date' => $targetMonth,
    ]);

    $service = new MonthlyReportService;
    $stats = $service->getConsultationStats($startDate, $endDate);

    expect($stats['total'])->toBe(10);
    expect($stats['completed'])->toBe(5);
    expect($stats['cancelled'])->toBe(2);
});

test('consultation statistics calculate no-show rate correctly', function () {
    $targetMonth = now()->subMonth();
    $startDate = $targetMonth->copy()->startOfMonth();
    $endDate = $targetMonth->copy()->endOfMonth();

    // 8 completed + 2 no-shows = 20% no-show rate
    Consultation::factory()->count(8)->completed()->create([
        'booking_date' => $targetMonth,
    ]);
    Consultation::factory()->count(2)->noShow()->create([
        'booking_date' => $targetMonth,
    ]);

    $service = new MonthlyReportService;
    $stats = $service->getConsultationStats($startDate, $endDate);

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

test('consultation statistics handle zero completed consultations', function () {
    $targetMonth = now()->subMonth();
    $startDate = $targetMonth->copy()->startOfMonth();
    $endDate = $targetMonth->copy()->endOfMonth();

    // Only pending consultations, no completed ones
    Consultation::factory()->count(5)->pending()->create([
        'booking_date' => $targetMonth,
    ]);

    $service = new MonthlyReportService;
    $stats = $service->getConsultationStats($startDate, $endDate);

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

test('consultation statistics count free and paid types', function () {
    $targetMonth = now()->subMonth();
    $startDate = $targetMonth->copy()->startOfMonth();
    $endDate = $targetMonth->copy()->endOfMonth();

    Consultation::factory()->count(4)->free()->create([
        'booking_date' => $targetMonth,
    ]);
    Consultation::factory()->count(6)->paid()->create([
        'booking_date' => $targetMonth,
    ]);

    $service = new MonthlyReportService;
    $stats = $service->getConsultationStats($startDate, $endDate);

    expect($stats['free'])->toBe(4);
    expect($stats['paid'])->toBe(6);
});

// ===========================================
// Service Tests - Timeline Statistics
// ===========================================

test('timeline statistics count active timelines correctly', function () {
    $targetMonth = now()->subMonth();
    $startDate = $targetMonth->copy()->startOfMonth();
    $endDate = $targetMonth->copy()->endOfMonth();

    Timeline::factory()->count(5)->active()->create([
        'created_at' => $targetMonth->copy()->subMonth(),
    ]);
    Timeline::factory()->count(2)->archived()->create([
        'created_at' => $targetMonth->copy()->subMonth(),
    ]);

    $service = new MonthlyReportService;
    $stats = $service->getTimelineStats($startDate, $endDate);

    expect($stats['active'])->toBe(5);
});

test('timeline statistics count new timelines in month', function () {
    $targetMonth = now()->subMonth();
    $startDate = $targetMonth->copy()->startOfMonth();
    $endDate = $targetMonth->copy()->endOfMonth();

    Timeline::factory()->count(3)->create([
        'created_at' => $targetMonth,
    ]);
    Timeline::factory()->count(2)->create([
        'created_at' => now()->subMonths(3),
    ]);

    $service = new MonthlyReportService;
    $stats = $service->getTimelineStats($startDate, $endDate);

    expect($stats['new'])->toBe(3);
});

test('timeline statistics count updates in month', function () {
    $targetMonth = now()->subMonth();
    $startDate = $targetMonth->copy()->startOfMonth();
    $endDate = $targetMonth->copy()->endOfMonth();

    $timeline = Timeline::factory()->create();
    TimelineUpdate::factory()->count(5)->create([
        'timeline_id' => $timeline->id,
        'created_at' => $targetMonth,
    ]);
    TimelineUpdate::factory()->count(2)->create([
        'timeline_id' => $timeline->id,
        'created_at' => now()->subMonths(3),
    ]);

    $service = new MonthlyReportService;
    $stats = $service->getTimelineStats($startDate, $endDate);

    expect($stats['updates'])->toBe(5);
});

// ===========================================
// Service Tests - Post Statistics
// ===========================================

test('post statistics count published posts in month', function () {
    $targetMonth = now()->subMonth();
    $startDate = $targetMonth->copy()->startOfMonth();
    $endDate = $targetMonth->copy()->endOfMonth();

    Post::factory()->count(4)->published()->create([
        'published_at' => $targetMonth,
    ]);
    Post::factory()->count(2)->published()->create([
        'published_at' => now()->subMonths(3),
    ]);

    $service = new MonthlyReportService;
    $stats = $service->getPostStats($startDate, $endDate);

    expect($stats['this_month'])->toBe(4);
    expect($stats['total'])->toBe(6);
});

// ===========================================
// Service Tests - Previous Month Comparison
// ===========================================

test('previous month comparison returns null when no prior data exists', function () {
    $targetMonth = now()->subMonth()->startOfMonth();

    $service = new MonthlyReportService;
    $comparison = $service->getPreviousMonthComparison($targetMonth);

    expect($comparison)->toBeNull();
});

test('previous month comparison returns data when prior month has data', function () {
    $targetMonth = now()->subMonth();
    $previousMonth = now()->subMonths(2);

    // Create data in the previous month
    User::factory()->count(3)->individual()->create([
        'created_at' => $previousMonth,
    ]);
    Consultation::factory()->count(5)->create([
        'booking_date' => $previousMonth,
    ]);

    $service = new MonthlyReportService;
    $comparison = $service->getPreviousMonthComparison($targetMonth->startOfMonth());

    expect($comparison)->not->toBeNull();
    expect($comparison['consultations'])->toBe(5);
    expect($comparison['clients'])->toBe(3);
});

// ===========================================
// Language Tests
// ===========================================

test('report respects admin language preference for Arabic', function () {
    $adminArabic = User::factory()->admin()->create(['preferred_language' => 'ar']);

    $this->actingAs($adminArabic);

    Volt::test('admin.reports.monthly-report')
        ->assertSee(__('report.monthly_report', [], 'ar'));
});

test('report respects admin language preference for English', function () {
    $adminEnglish = User::factory()->admin()->create(['preferred_language' => 'en']);

    app()->setLocale('en');
    $this->actingAs($adminEnglish);

    Volt::test('admin.reports.monthly-report')
        ->assertSee('Monthly Statistics Report');
});

// ===========================================
// UI Elements Tests
// ===========================================

test('monthly report page shows table of contents preview', function () {
    $this->actingAs($this->admin);

    Volt::test('admin.reports.monthly-report')
        ->assertSee(__('report.table_of_contents'))
        ->assertSee(__('report.executive_summary'))
        ->assertSee(__('report.user_statistics'))
        ->assertSee(__('report.consultation_statistics'))
        ->assertSee(__('report.timeline_statistics'))
        ->assertSee(__('report.post_statistics'))
        ->assertSee(__('report.trends_chart'));
});

test('monthly report page shows generate button', function () {
    $this->actingAs($this->admin);

    Volt::test('admin.reports.monthly-report')
        ->assertSee(__('report.generate'));
});

test('monthly report page shows period selector', function () {
    $this->actingAs($this->admin);

    Volt::test('admin.reports.monthly-report')
        ->assertSee(__('report.select_period'));
});
