<?php

declare(strict_types=1);

namespace App\Service\WorkHours;

use App\Dto\WorkHours\NightContingentRow;
use App\Entity\Employee;
use App\Repository\Contract\WorkHourReadRepositoryInterface;
use App\Service\Contracts\EmployeeContractResolver;
use DateTimeImmutable;

/**
 * Construit, par employe, les totaux mensuels d'heures de nuit et le nombre de
 * nuits travaillees (>= 4h de nuit dans la journee). Fenetre 21h->6h via
 * NightHoursCalculator. Conducteurs : minutes saisies (nightHoursMinutes).
 * Aucun credit absence/ferie : seules les heures reellement travaillees comptent.
 */
final readonly class NightContingentExportBuilder
{
    private const int NIGHT_DAY_THRESHOLD_MINUTES = 240;

    public function __construct(
        private WorkHourReadRepositoryInterface $workHourRepository,
        private EmployeeContractResolver $contractResolver,
        private NightHoursCalculator $nightHoursCalculator,
    ) {}

    /**
     * @param list<Employee> $employees
     *
     * @return list<NightContingentRow>
     */
    public function buildRows(array $employees, int $year): array
    {
        $from = new DateTimeImmutable(sprintf('%d-01-01', $year));
        $to   = new DateTimeImmutable(sprintf('%d-12-31', $year));

        $workHours = $this->workHourRepository->findByDateRangeAndEmployees($from, $to, $employees);

        $byEmployee = [];
        foreach ($workHours as $wh) {
            $employeeId = $wh->getEmployee()?->getId();
            if (null === $employeeId) {
                continue;
            }
            $byEmployee[$employeeId][] = $wh;
        }

        $days = [];
        foreach ($workHours as $wh) {
            $days[$wh->getWorkDate()->format('Y-m-d')] = true;
        }
        $days = array_keys($days);

        $driverMap = $this->contractResolver->resolveIsDriverForEmployeesAndDays($employees, $days);

        $rows = [];
        foreach ($employees as $employee) {
            $employeeId = $employee->getId();
            if (null === $employeeId) {
                continue;
            }

            $months = [];
            for ($m = 1; $m <= 12; ++$m) {
                $months[$m] = ['nightMinutes' => 0, 'nightDays' => 0];
            }

            foreach ($byEmployee[$employeeId] ?? [] as $wh) {
                $date     = DateTimeImmutable::createFromInterface($wh->getWorkDate());
                $ymd      = $date->format('Y-m-d');
                $isDriver = $driverMap[$employeeId][$ymd] ?? false;
                $nightMin = $this->nightHoursCalculator->nightMinutesForWorkHour($wh, $isDriver);
                if ($nightMin <= 0) {
                    continue;
                }

                $month = (int) $date->format('n');
                $months[$month]['nightMinutes'] += $nightMin;
                if ($nightMin >= self::NIGHT_DAY_THRESHOLD_MINUTES) {
                    ++$months[$month]['nightDays'];
                }
            }

            $rows[] = new NightContingentRow(
                employeeId: $employeeId,
                employeeName: trim($employee->getLastName().' '.$employee->getFirstName()),
                months: $months,
            );
        }

        return $rows;
    }
}
