<?php

namespace Tests\Unit;

use App\Models\Company;
use App\Models\Leave;
use App\Models\LeaveType;
use App\Models\LeaveTypeRule;
use App\Models\User;
use App\Services\Leave\LeaveDashboardStatsService;
use App\Services\Leave\LeaveLedgerService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class LeaveDashboardStatsServiceTest extends TestCase
{
    use RefreshDatabase;

    public function test_leave_stats_group_approved_days_by_weekday_type_and_month(): void
    {
        $company = Company::query()->create([
            'name' => 'Stats Co',
            'short_name' => 'SC',
            'email' => 'stats@co.test',
            'status' => 'active',
        ]);

        $user = User::factory()->create([
            'company_id' => $company->id,
            'user_type' => User::USER_TYPE_STAFF,
        ]);

        $earned = LeaveType::query()->create([
            'company_id' => $company->id,
            'name' => 'Earned Leave',
            'short_code' => 'EL',
            'is_paid' => true,
            'total_leaves' => 20,
            'leave_count' => 20,
            'apply_to_all' => true,
        ]);
        LeaveTypeRule::query()->create([
            'company_id' => $company->id,
            'leave_type_id' => $earned->id,
            'accrual_mode' => LeaveLedgerService::ACCRUAL_YEARLY,
            'carry_forward_enabled' => true,
            'carry_forward_limit' => 5,
            'approval_levels' => 1,
        ]);

        // Thursday 2026-09-10 and Friday 2026-09-11
        Leave::query()->create([
            'company_id' => $company->id,
            'user_id' => $user->id,
            'leave_type_id' => $earned->id,
            'start_date' => '2026-09-10',
            'end_date' => '2026-09-11',
            'total_days' => 2,
            'status' => 'approved',
            'reason' => 'Trip',
            'is_paid' => true,
        ]);

        $stats = app(LeaveDashboardStatsService::class)->leaveStatsForUser($user, 2026);

        $this->assertSame(['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], $stats['weekly']['labels']);
        $this->assertEqualsWithDelta(1.0, $stats['weekly']['data'][3], 0.01); // Thu
        $this->assertEqualsWithDelta(1.0, $stats['weekly']['data'][4], 0.01); // Fri
        $this->assertSame(['Earned Leave'], $stats['by_type']['labels']);
        $this->assertEqualsWithDelta(2.0, $stats['by_type']['data'][0], 0.01);
        $this->assertEqualsWithDelta(2.0, $stats['monthly']['data'][8], 0.01); // Sep index 8
    }

    public function test_rule_summaries_include_accrual_and_carryover_chips(): void
    {
        $company = Company::query()->create([
            'name' => 'Rules Co',
            'short_name' => 'RC',
            'email' => 'rules@co.test',
            'status' => 'active',
        ]);

        $user = User::factory()->create([
            'company_id' => $company->id,
            'user_type' => User::USER_TYPE_STAFF,
        ]);

        $type = LeaveType::query()->create([
            'company_id' => $company->id,
            'name' => 'Casual',
            'short_code' => 'CL',
            'is_paid' => true,
            'total_leaves' => 12,
            'leave_count' => 12,
            'apply_to_all' => true,
        ]);
        LeaveTypeRule::query()->create([
            'company_id' => $company->id,
            'leave_type_id' => $type->id,
            'accrual_mode' => LeaveLedgerService::ACCRUAL_MONTHLY,
            'carry_forward_enabled' => true,
            'carry_forward_limit' => 3,
            'approval_levels' => 1,
        ]);

        $ledger = app(LeaveLedgerService::class);
        $balances = $ledger->balancesForUser($user, 2026);
        $summaries = app(LeaveDashboardStatsService::class)->ruleSummaries($user, $balances);

        $this->assertNotEmpty($summaries);
        $chips = $summaries[0]['chips'];
        $this->assertTrue(collect($chips)->contains(fn ($c) => str_contains($c, 'Monthly')));
        $this->assertTrue(collect($chips)->contains(fn ($c) => str_contains($c, 'Carryover')));
    }
}
