<?php

declare(strict_types=1);

namespace App\Tests\Service\WorkHours;

use App\Entity\Employee;
use App\Entity\WorkHour;
use App\Repository\Contract\WorkHourReadRepositoryInterface;
use App\Service\Contracts\EmployeeContractResolver;
use App\Service\WorkHours\NightContingentExportBuilder;
use App\Service\WorkHours\NightHoursCalculator;
use DateTimeImmutable;
use PHPUnit\Framework\TestCase;
use ReflectionProperty;

/**
 * @internal
 */
final class NightContingentExportBuilderTest extends TestCase
{
    public function testAggregatesNightMinutesAndDaysPerMonth(): void
    {
        $employee = $this->makeEmployee(1, 'Dupont', 'Jean');

        // Janvier : un jour 4h de nuit (>=240 -> 1 jour) + un jour 3h59 (<240 -> 0 jour).
        $whFull = new WorkHour()->setEmployee($employee)
            ->setWorkDate(new DateTimeImmutable('2026-01-10'))
            ->setEveningFrom('21:00')->setEveningTo('01:00')   // 240 min nuit
        ;
        $whShort = new WorkHour()->setEmployee($employee)
            ->setWorkDate(new DateTimeImmutable('2026-01-11'))
            ->setEveningFrom('21:00')->setEveningTo('00:59')   // 239 min nuit
        ;

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

        $contractResolver = $this->createStub(EmployeeContractResolver::class);
        $contractResolver->method('resolveIsDriverForEmployeesAndDays')->willReturn([
            1 => ['2026-01-10' => false, '2026-01-11' => false],
        ]);

        $builder = new NightContingentExportBuilder(
            $workHourRepo,
            $contractResolver,
            new NightHoursCalculator(),
        );

        $rows = $builder->buildRows([$employee], 2026);

        self::assertCount(1, $rows);
        self::assertSame(479, $rows[0]->months[1]['nightMinutes']); // 240 + 239
        self::assertSame(1, $rows[0]->months[1]['nightDays']);      // seul le jour >=240
        self::assertSame(0, $rows[0]->months[2]['nightMinutes']);   // fevrier vide
        self::assertSame(0, $rows[0]->months[2]['nightDays']);
    }

    public function testDriverUsesManualNightMinutes(): void
    {
        $employee = $this->makeEmployee(2, 'Martin', 'Paul');

        $wh = new WorkHour()->setEmployee($employee)
            ->setWorkDate(new DateTimeImmutable('2026-03-05'))
            ->setNightHoursMinutes(300)
            ->setMorningFrom('08:00')->setMorningTo('12:00') // ignore (driver)
        ;

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

        $contractResolver = $this->createStub(EmployeeContractResolver::class);
        $contractResolver->method('resolveIsDriverForEmployeesAndDays')->willReturn([
            2 => ['2026-03-05' => true],
        ]);

        $builder = new NightContingentExportBuilder(
            $workHourRepo,
            $contractResolver,
            new NightHoursCalculator(),
        );

        $rows = $builder->buildRows([$employee], 2026);

        self::assertSame(300, $rows[0]->months[3]['nightMinutes']);
        self::assertSame(1, $rows[0]->months[3]['nightDays']); // 300 >= 240
    }

    public function testEmployeeWithoutWorkHoursYieldsAllZeroMonths(): void
    {
        $employee = $this->makeEmployee(3, 'Durand', 'Marie');

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

        $contractResolver = $this->createStub(EmployeeContractResolver::class);
        $contractResolver->method('resolveIsDriverForEmployeesAndDays')->willReturn([]);

        $builder = new NightContingentExportBuilder(
            $workHourRepo,
            $contractResolver,
            new NightHoursCalculator(),
        );

        $rows = $builder->buildRows([$employee], 2026);

        self::assertCount(1, $rows);
        for ($m = 1; $m <= 12; ++$m) {
            self::assertSame(0, $rows[0]->months[$m]['nightMinutes']);
            self::assertSame(0, $rows[0]->months[$m]['nightDays']);
        }
    }

    private function makeEmployee(int $id, string $last, string $first): Employee
    {
        $employee = new Employee();
        $employee->setLastName($last)->setFirstName($first);
        $ref = new ReflectionProperty(Employee::class, 'id');
        $ref->setValue($employee, $id);

        return $employee;
    }
}
