<?php

namespace Tests\Unit;

use App\Models\Allocation;
use App\Models\Project;
use App\Models\ProjectMonthPlan;
use App\Models\Role;
use App\Models\TeamMember;
use App\Services\VarianceCalculator;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class VarianceCalculatorTest extends TestCase
{
    use RefreshDatabase;

    private VarianceCalculator $calculator;

    protected function setUp(): void
    {
        parent::setUp();
        $this->calculator = new VarianceCalculator;
    }

    // 2.1: Unit test - row variance uses selected month planned value
    public function test_row_variance_uses_planned_month_value(): void
    {
        $project = Project::factory()->create();

        // Create month plan for Jan 2026
        ProjectMonthPlan::create([
            'project_id' => $project->id,
            'month' => '2026-01-01',
            'planned_hours' => 100,
        ]);

        // Create allocation totaling 120 hours using factory for proper date handling
        $allocation = Allocation::factory()->create([
            'project_id' => $project->id,
            'team_member_id' => null, // untracked
            'month' => '2026-01-01',
            'allocated_hours' => 120,
        ]);

        $result = $this->calculator->calculateRowVariance($project->id, '2026-01');

        $this->assertEquals(120, $result['allocated_total']);
        $this->assertEquals(100, $result['planned_month']);
        $this->assertEquals(20, $result['variance']);
        $this->assertEquals('OVER', $result['status']);
    }

    // 2.2: Unit test - blank month plan treated as zero for row variance
    public function test_blank_month_plan_treated_as_zero(): void
    {
        $project = Project::factory()->create();

        // No month plan created (blank)

        // Create allocation of 50 hours
        Allocation::factory()->create([
            'project_id' => $project->id,
            'team_member_id' => null,
            'month' => '2026-01-01',
            'allocated_hours' => 50,
        ]);

        $result = $this->calculator->calculateRowVariance($project->id, '2026-01');

        // Blank plan = 0, so variance = 50 - 0 = 50
        $this->assertEquals(50, $result['allocated_total']);
        $this->assertEquals(0, $result['planned_month']);
        $this->assertEquals(50, $result['variance']);
        $this->assertEquals('OVER', $result['status']);
    }

    // 2.3: Unit test - column variance uses member month capacity
    public function test_column_variance_uses_member_capacity(): void
    {
        $role = Role::factory()->create();
        $teamMember = TeamMember::factory()->create(['role_id' => $role->id]);

        // Create allocation for member
        Allocation::factory()->create([
            'project_id' => Project::factory()->create()->id,
            'team_member_id' => $teamMember->id,
            'month' => '2026-01-01',
            'allocated_hours' => 120,
        ]);

        // Mock capacity service - we'll test basic logic here
        $mockCapacityService = $this->createMock(\App\Services\CapacityService::class);
        $mockCapacityService->method('calculateIndividualCapacity')
            ->willReturn(['hours' => 160]);

        $result = $this->calculator->calculateColumnVariance($teamMember->id, '2026-01', $mockCapacityService);

        $this->assertEquals(120, $result['allocated']);
        $this->assertEquals(160, $result['capacity']);
        $this->assertEquals(-40, $result['variance']);
        $this->assertEquals('UNDER', $result['status']);
    }

    // Additional test: MATCH status when variance is zero
    public function test_determine_status_returns_match_when_variance_is_zero(): void
    {
        $status = $this->calculator->determineStatus(0);
        $this->assertEquals('MATCH', $status);
    }

    // Additional test: get planned hours returns zero for non-existent plan
    public function test_get_planned_hours_returns_zero_for_no_plan(): void
    {
        $project = Project::factory()->create();

        $plannedHours = $this->calculator->getPlannedHoursForMonth($project->id, '2026-01');

        $this->assertEquals(0, $plannedHours);
    }

    // Additional test: untracked allocation is included in row variance
    public function test_untracked_allocation_included_in_row_variance(): void
    {
        $project = Project::factory()->create();

        // Create month plan
        ProjectMonthPlan::create([
            'project_id' => $project->id,
            'month' => '2026-01-01',
            'planned_hours' => 100,
        ]);

        // Create tracked allocation
        $role = Role::factory()->create();
        $teamMember = TeamMember::factory()->create(['role_id' => $role->id]);

        Allocation::factory()->create([
            'project_id' => $project->id,
            'team_member_id' => $teamMember->id,
            'month' => '2026-01-01',
            'allocated_hours' => 60,
        ]);

        // Create untracked allocation (team_member_id = null)
        Allocation::factory()->create([
            'project_id' => $project->id,
            'team_member_id' => null,
            'month' => '2026-01-01',
            'allocated_hours' => 60,
        ]);

        $result = $this->calculator->calculateRowVariance($project->id, '2026-01');

        // Total should include both tracked and untracked
        $this->assertEquals(120, $result['allocated_total']);
        $this->assertEquals(20, $result['variance']);
        $this->assertEquals('OVER', $result['status']);
    }
}
