<?php

declare(strict_types=1);

namespace App\Tests\Service\WorkHours;

use App\Entity\Contract;
use App\Entity\Employee;
use App\Entity\EmployeeContractPeriod;
use App\Entity\EmployeeRttPayment;
use App\Enum\TrackingMode;
use App\Repository\EmployeeRttPaymentRepository;
use App\Service\WorkHours\OvertimeContingentExportBuilder;
use App\Service\WorkHours\OvertimePaidContingentCalculator;
use App\Service\WorkHours\StructuralOvertimeContingentCalculator;
use DateTimeImmutable;
use PHPUnit\Framework\TestCase;
use ReflectionProperty;

/**
 * @internal
 */
final class OvertimeContingentExportBuilderTest extends TestCase
{
    public function testBuildsRowsWithMonthlyTotalsAndCap(): void
    {
        // isDriver est résolu via le contrat courant : on le force par une
        // sous-classe anonyme pour rester en test unitaire (sans BDD).
        $driverEmp = new class extends Employee {
            public function getIsDriver(): bool
            {
                return true;
            }
        };
        $driverEmp->setLastName('Martin')->setFirstName('Luc');
        $idRef = new ReflectionProperty(Employee::class, 'id');
        $idRef->setValue($driverEmp, 7);

        // Paiement : exercice 2027, mois 9 -> civil 2026, mois 9 ; base 100+20.
        $payment = new EmployeeRttPayment()
            ->setEmployee($driverEmp)
            ->setYear(2027)->setMonth(9)
            ->setBase25Minutes(100)->setBase50Minutes(20)
        ;

        $repo = $this->createStub(EmployeeRttPaymentRepository::class);
        $repo->method('findByEmployeesAndYears')->willReturn([$payment]);

        $builder = new OvertimeContingentExportBuilder($repo, new OvertimePaidContingentCalculator(), new StructuralOvertimeContingentCalculator());

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

        self::assertCount(1, $rows);
        self::assertSame(7, $rows[0]->employeeId);
        self::assertSame('Martin Luc', $rows[0]->employeeName);
        self::assertSame(120, $rows[0]->months[9]);
        self::assertSame(0, $rows[0]->months[1]);
        self::assertSame(120, $rows[0]->totalMinutes);
        self::assertSame(350, $rows[0]->capHours); // chauffeur
    }

    public function testEmployeeWithNoPaymentsYieldsZeroRow(): void
    {
        $emp = new Employee();
        $emp->setLastName('Durand')->setFirstName('Alice');
        $idRef = new ReflectionProperty(Employee::class, 'id');
        $idRef->setValue($emp, 99);

        $repo = $this->createStub(EmployeeRttPaymentRepository::class);
        $repo->method('findByEmployeesAndYears')->willReturn([]);

        $builder = new OvertimeContingentExportBuilder($repo, new OvertimePaidContingentCalculator(), new StructuralOvertimeContingentCalculator());
        $rows    = $builder->buildRows([$emp], 2026);

        self::assertCount(1, $rows);
        self::assertSame(0, $rows[0]->totalMinutes);
        self::assertSame(0, $rows[0]->months[6]);
        self::assertSame(220, $rows[0]->capHours); // non-driver
    }

    public function testStructuralHoursOf39hAreAddedToPaidBase(): void
    {
        $contract = new Contract()
            ->setName('CDI')
            ->setTrackingMode(TrackingMode::TIME)
            ->setWeeklyHours(39)
        ;
        $period = new EmployeeContractPeriod()
            ->setContract($contract)
            ->setStartDate(new DateTimeImmutable('2020-01-01'))
        ;
        $emp = new Employee();
        $emp->setLastName('Petit')->setFirstName('Marc');
        $emp->getContractPeriods()->add($period);
        $idRef = new ReflectionProperty(Employee::class, 'id');
        $idRef->setValue($emp, 11);

        $repo = $this->createStub(EmployeeRttPaymentRepository::class);
        $repo->method('findByEmployeesAndYears')->willReturn([]);

        $builder = new OvertimeContingentExportBuilder($repo, new OvertimePaidContingentCalculator(), new StructuralOvertimeContingentCalculator());
        $rows    = $builder->buildRows([$emp], 2026);

        // Aucun paiement RTT, mais 12 × 1040 min de structurel (39h plein sur l'année).
        self::assertSame(1040, $rows[0]->months[1]);
        self::assertSame(12 * 1040, $rows[0]->totalMinutes);
    }
}
