<?php

use App\Models\Allocation;
use App\Models\Holiday;
use App\Models\Role;
use App\Models\TeamMember;
use App\Services\CapacityService;
use App\Services\UtilizationService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

/**
 * @mixin \Tests\TestCase
 */
uses(TestCase::class, RefreshDatabase::class);

// ============================================================================
// 7.1.12 UtilizationService calculates running utilization (YTD)
// ============================================================================

test('7.1.12a UtilizationService calculates running utilization YTD', function () {
    $role = Role::factory()->create();
    $member = TeamMember::factory()->create(['role_id' => $role->id, 'active' => true]);

    // Create allocations for Jan, Feb, Mar
    Allocation::factory()->create([
        'team_member_id' => $member->id,
        'month' => '2026-01-01',
        'allocated_hours' => 140,
    ]);
    Allocation::factory()->create([
        'team_member_id' => $member->id,
        'month' => '2026-02-01',
        'allocated_hours' => 150,
    ]);
    Allocation::factory()->create([
        'team_member_id' => $member->id,
        'month' => '2026-03-01',
        'allocated_hours' => 160,
    ]);

    $service = app(UtilizationService::class);
    $result = $service->calculateRunningUtilization($member->id, '2026-03');

    // Expected: YTD allocated = 140 + 150 + 160 = 450
    // Expected: YTD capacity = varies by working days per month
    expect($result['allocated_ytd'])->toBe(450.0)
        ->and($result['months_included'])->toBe(3)
        ->and($result['utilization'])->toBeGreaterThan(80.0);
});

test('7.1.12b Running utilization at start of year (January only)', function () {
    $role = Role::factory()->create();
    $member = TeamMember::factory()->create(['role_id' => $role->id, 'active' => true]);

    Allocation::factory()->create([
        'team_member_id' => $member->id,
        'month' => '2026-01-01',
        'allocated_hours' => 120,
    ]);

    $service = app(UtilizationService::class);
    $result = $service->calculateRunningUtilization($member->id, '2026-01');

    // Only January (Jan 2026 has 21 working days = 176 hours capacity)
    // 120 / 176 = 68.2%
    expect($result['months_included'])->toBe(1)
        ->and($result['allocated_ytd'])->toBe(120.0)
        ->and($result['utilization'])->toBeGreaterThan(60.0);
});

// ============================================================================
// 7.1.13 UtilizationService calculates overall utilization (monthly)
// ============================================================================

test('7.1.13a UtilizationService calculates overall utilization monthly', function () {
    $role = Role::factory()->create();
    $member = TeamMember::factory()->create(['role_id' => $role->id, 'active' => true]);

    Allocation::factory()->create([
        'team_member_id' => $member->id,
        'month' => '2026-02-01',
        'allocated_hours' => 140,
    ]);

    $service = app(UtilizationService::class);
    $result = $service->calculateOverallUtilization($member->id, '2026-02');

    // Feb 2026: 20 working days = 160 hours capacity
    // 140 / 160 * 100 = 87.5%
    expect($result['capacity'])->toBe(160.0)
        ->and($result['allocated'])->toBe(140.0)
        ->and($result['utilization'])->toBe(87.5);
});

test('7.1.13b Full utilization 100%', function () {
    $role = Role::factory()->create();
    $member = TeamMember::factory()->create(['role_id' => $role->id, 'active' => true]);

    Allocation::factory()->create([
        'team_member_id' => $member->id,
        'month' => '2026-02-01',
        'allocated_hours' => 160,
    ]);

    $service = app(UtilizationService::class);
    $result = $service->calculateOverallUtilization($member->id, '2026-02');

    expect($result['utilization'])->toBe(100.0);
});

test('7.1.13c Over-utilization >100%', function () {
    $role = Role::factory()->create();
    $member = TeamMember::factory()->create(['role_id' => $role->id, 'active' => true]);

    Allocation::factory()->create([
        'team_member_id' => $member->id,
        'month' => '2026-02-01',
        'allocated_hours' => 180,
    ]);

    $service = app(UtilizationService::class);
    $result = $service->calculateOverallUtilization($member->id, '2026-02');

    // 180 / 160 * 100 = 112.5%
    expect($result['utilization'])->toBe(112.5);
});

// ============================================================================
// 7.1.14 UtilizationService handles edge cases
// ============================================================================

test('7.1.14a Zero capacity returns zero utilization', function () {
    $role = Role::factory()->create();
    $member = TeamMember::factory()->create(['role_id' => $role->id, 'active' => true]);

    // Create a holiday for every working day in February to make capacity zero
    foreach (range(1, 28) as $day) {
        $date = sprintf('2026-02-%02d', $day);
        $carbon = \Carbon\Carbon::parse($date);
        if (! $carbon->isWeekend()) {
            Holiday::create(['date' => $date, 'name' => "Holiday $day", 'description' => 'Test']);
        }
    }

    Allocation::factory()->create([
        'team_member_id' => $member->id,
        'month' => '2026-02-01',
        'allocated_hours' => 100,
    ]);

    $service = app(UtilizationService::class);
    $result = $service->calculateOverallUtilization($member->id, '2026-02');

    expect($result['capacity'])->toBe(0.0)
        ->and($result['utilization'])->toBe(0.0);
});

test('7.1.14b No allocations returns zero utilization', function () {
    $role = Role::factory()->create();
    $member = TeamMember::factory()->create(['role_id' => $role->id, 'active' => true]);

    $service = app(UtilizationService::class);
    $result = $service->calculateOverallUtilization($member->id, '2026-02');

    expect($result['allocated'])->toBe(0.0)
        ->and($result['utilization'])->toBe(0.0);
});

test('7.1.14c Team utilization excludes inactive members', function () {
    $role = Role::factory()->create();
    $activeMember = TeamMember::factory()->create(['role_id' => $role->id, 'active' => true]);
    $inactiveMember = TeamMember::factory()->create(['role_id' => $role->id, 'active' => false]);

    Allocation::factory()->create([
        'team_member_id' => $activeMember->id,
        'month' => '2026-02-01',
        'allocated_hours' => 140,
    ]);
    Allocation::factory()->create([
        'team_member_id' => $inactiveMember->id,
        'month' => '2026-02-01',
        'allocated_hours' => 160,
    ]);

    $service = app(UtilizationService::class);
    $result = $service->calculateTeamUtilization('2026-02');

    // Only active member counted
    expect($result['member_count'])->toBe(1);
});

// ============================================================================
// 7.1.15 Color coding logic
// ============================================================================

test('7.1.15a Low utilization (< 70%) is gray', function () {
    $service = app(UtilizationService::class);

    expect($service->getUtilizationIndicator(0))->toBe('gray')
        ->and($service->getUtilizationIndicator(50))->toBe('gray')
        ->and($service->getUtilizationIndicator(69.9))->toBe('gray');
});

test('7.1.15b Low utilization (70-80%) is blue', function () {
    $service = app(UtilizationService::class);

    expect($service->getUtilizationIndicator(70))->toBe('blue')
        ->and($service->getUtilizationIndicator(75))->toBe('blue')
        ->and($service->getUtilizationIndicator(79.9))->toBe('blue');
});

test('7.1.15c Optimal utilization (80-100%) is green', function () {
    $service = app(UtilizationService::class);

    expect($service->getUtilizationIndicator(80))->toBe('green')
        ->and($service->getUtilizationIndicator(90))->toBe('green')
        ->and($service->getUtilizationIndicator(100))->toBe('green');
});

test('7.1.15d High utilization (100-110%) is yellow', function () {
    $service = app(UtilizationService::class);

    expect($service->getUtilizationIndicator(100.1))->toBe('yellow')
        ->and($service->getUtilizationIndicator(105))->toBe('yellow')
        ->and($service->getUtilizationIndicator(110))->toBe('yellow');
});

test('7.1.15e Over-utilization (> 110%) is red', function () {
    $service = app(UtilizationService::class);

    expect($service->getUtilizationIndicator(110.1))->toBe('red')
        ->and($service->getUtilizationIndicator(120))->toBe('red')
        ->and($service->getUtilizationIndicator(200))->toBe('red');
});

// ============================================================================
// Additional coverage tests
// ============================================================================

test('7.1.16 getUtilizationData combines overall and running', function () {
    $role = Role::factory()->create();
    $member = TeamMember::factory()->create(['role_id' => $role->id, 'active' => true]);

    Allocation::factory()->create([
        'team_member_id' => $member->id,
        'month' => '2026-02-01',
        'allocated_hours' => 140,
    ]);

    $service = app(UtilizationService::class);
    $result = $service->getUtilizationData($member->id, '2026-02');

    expect($result)->toHaveKeys(['overall', 'running'])
        ->and($result['overall'])->toHaveKeys(['capacity', 'allocated', 'utilization', 'indicator'])
        ->and($result['running'])->toHaveKeys(['capacity_ytd', 'allocated_ytd', 'utilization', 'indicator', 'months_included']);
});

test('7.1.17 getUtilizationTrend returns monthly data', function () {
    $role = Role::factory()->create();
    $member = TeamMember::factory()->create(['role_id' => $role->id, 'active' => true]);

    Allocation::factory()->create([
        'team_member_id' => $member->id,
        'month' => '2026-01-01',
        'allocated_hours' => 140,
    ]);
    Allocation::factory()->create([
        'team_member_id' => $member->id,
        'month' => '2026-02-01',
        'allocated_hours' => 150,
    ]);
    Allocation::factory()->create([
        'team_member_id' => $member->id,
        'month' => '2026-03-01',
        'allocated_hours' => 160,
    ]);

    $service = app(UtilizationService::class);
    $result = $service->getUtilizationTrend($member->id, '2026-01', '2026-03');

    expect($result)->toHaveCount(3)
        ->and($result[0])->toHaveKeys(['month', 'utilization', 'indicator', 'capacity', 'allocated'])
        ->and($result[0]['month'])->toBe('2026-01')
        ->and($result[2]['month'])->toBe('2026-03');
});

test('7.1.18 calculateTeamRunningUtilization calculates YTD team average', function () {
    $role = Role::factory()->create();
    $memberA = TeamMember::factory()->create(['role_id' => $role->id, 'active' => true]);
    $memberB = TeamMember::factory()->create(['role_id' => $role->id, 'active' => true]);

    // Jan 2026 has 21 working days = 176 hours capacity
    // Member A: 140/176 = 79.5% utilization
    Allocation::factory()->create([
        'team_member_id' => $memberA->id,
        'month' => '2026-01-01',
        'allocated_hours' => 140,
    ]);

    // Member B: 150/176 = 85.2% utilization
    Allocation::factory()->create([
        'team_member_id' => $memberB->id,
        'month' => '2026-01-01',
        'allocated_hours' => 150,
    ]);

    $service = app(UtilizationService::class);
    $result = $service->calculateTeamRunningUtilization('2026-01');

    // Average: (79.5 + 85.2) / 2 = 82.35
    expect($result['member_count'])->toBe(2)
        ->and($result['average_utilization'])->toBe(82.4);
});
