<?php

declare(strict_types=1);

namespace App\Tests\Service\WorkHours;

use App\Entity\Contract;
use App\Entity\Employee;
use App\Entity\WorkHour;
use App\Repository\Contract\AbsenceReadRepositoryInterface;
use App\Repository\Contract\WorkHourReadRepositoryInterface;
use App\Service\Contracts\EmployeeContractResolver;
use App\Service\PublicHolidayServiceInterface;
use App\Service\WorkHours\AbsenceSegmentsResolver;
use App\Service\WorkHours\DailyReferenceMinutesResolver;
use App\Service\WorkHours\HolidayVirtualHoursResolver;
use App\Service\WorkHours\NightHoursCalculator;
use App\Service\WorkHours\WorkedHoursCreditPolicy;
use App\Service\WorkHours\YearlyHoursExportBuilder;
use DateTimeImmutable;
use PHPUnit\Framework\TestCase;
use ReflectionProperty;

/**
 * @internal
 */
final class YearlyHoursDayRowsTest extends TestCase
{
    public function testTimeContractRowComputesHoursAndExcludesNoContract(): void
    {
        $date = new DateTimeImmutable('2026-06-08'); // lundi

        $contract = new Contract();
        $contract->setName('35h');
        $contract->setTrackingMode(Contract::TRACKING_TIME);
        $contract->setWeeklyHours(35);

        $withContract = new Employee();
        $withContract->setFirstName('Jean')->setLastName('Dupont');
        $this->setEmployeeId($withContract, 1);

        $noContract = new Employee();
        $noContract->setFirstName('Paul')->setLastName('Martin');
        $this->setEmployeeId($noContract, 2);

        $workHour = new WorkHour();
        $workHour->setEmployee($withContract)
            ->setWorkDate($date)
            ->setMorningFrom('08:00')->setMorningTo('12:00')
            ->setAfternoonFrom('13:00')->setAfternoonTo('17:00')
        ;

        $workHourRepo = $this->createStub(WorkHourReadRepositoryInterface::class);
        $workHourRepo->method('findByDateRangeAndEmployees')->willReturn([$workHour]);

        $absenceRepo = $this->createStub(AbsenceReadRepositoryInterface::class);
        $absenceRepo->method('findForPrint')->willReturn([]);

        $contractResolver = $this->createStub(EmployeeContractResolver::class);
        $contractResolver->method('resolveForEmployeesAndDays')->willReturn([
            1 => ['2026-06-08' => $contract],
            2 => ['2026-06-08' => null],
        ]);
        $contractResolver->method('resolveIsDriverForEmployeesAndDays')->willReturn([
            1 => ['2026-06-08' => false],
            2 => ['2026-06-08' => false],
        ]);
        $contractResolver->method('resolveWorkDaysMinutesForEmployeesAndDays')->willReturn([
            1 => ['2026-06-08' => null],
            2 => ['2026-06-08' => null],
        ]);

        $holidayService = $this->createStub(PublicHolidayServiceInterface::class);
        $holidayService->method('getHolidaysDayByYears')->willReturn([]);

        // No holiday on this Monday → virtual credit resolves to 0 via the real resolver.
        $virtualResolver = new HolidayVirtualHoursResolver(
            new DailyReferenceMinutesResolver(),
            $holidayService,
            $contractResolver,
        );

        $builder = new YearlyHoursExportBuilder(
            $workHourRepo,
            $absenceRepo,
            $contractResolver,
            new AbsenceSegmentsResolver(),
            new WorkedHoursCreditPolicy($contractResolver, new DailyReferenceMinutesResolver()),
            $holidayService,
            $virtualResolver,
            new NightHoursCalculator(),
        );

        $rows = $builder->buildDayRowsForEmployees([$withContract, $noContract], $date);

        self::assertCount(1, $rows);
        self::assertSame(1, $rows[0]['employeeId']);
        self::assertSame('Dupont Jean', $rows[0]['employeeName']);
        self::assertSame('08:00', $rows[0]['morningFrom']);
        self::assertSame('17:00', $rows[0]['afternoonTo']);
        self::assertSame('8h', $rows[0]['total']);
        self::assertSame('8h', $rows[0]['dayHours']);
        self::assertSame('', $rows[0]['nightHours']);
        self::assertNull($rows[0]['statut']);
        self::assertNull($rows[0]['statutLabel']);
        self::assertNull($rows[0]['statutColor']);
        self::assertFalse($rows[0]['isWeekend']);
    }

    private function setEmployeeId(Employee $employee, int $id): void
    {
        $ref = new ReflectionProperty(Employee::class, 'id');
        $ref->setAccessible(true);
        $ref->setValue($employee, $id);
    }
}
