<?php

declare(strict_types=1);

namespace App\Service\WorkHours;

use App\Entity\Employee;
use App\Enum\ContractType;
use DateTimeImmutable;

/**
 * Heures supplémentaires « structurelles » payées chaque mois pour les contrats
 * au-dessus de 35h (hors forfait/intérim) : les (weeklyHours − 35) h/semaine
 * au-delà de la durée légale sont payées chaque mois, lissées sur l'année :
 * (weeklyHours − 35) × 52/12 h/mois = (weeklyHours − 35) × 260 min/mois.
 *
 * Ces heures ne transitent pas par les paiements RTT (la référence d'un 39h est
 * 39h, pas 35h) mais comptent dans le contingent légal d'heures supplémentaires.
 * Elles sont proratisées aux jours réellement sous contrat dans chaque mois.
 */
final readonly class StructuralOvertimeContingentCalculator
{
    /** 60 min × 52 semaines / 12 mois = minutes mensuelles par heure hebdo au-delà de 35h. */
    private const int MINUTES_PER_WEEKLY_HOUR_PER_MONTH = 260;

    /**
     * @return array<int, int> clé 1..12 -> minutes structurelles payées (proratisées)
     */
    public function monthlyStructuralMinutes(Employee $employee, int $civilYear): array
    {
        $accumulated = array_fill(1, 12, 0.0);

        foreach ($employee->getContractPeriods() as $period) {
            $contract = $period->getContract();
            if (null === $contract) {
                continue;
            }

            $type = $contract->getType();
            if (ContractType::FORFAIT === $type || ContractType::INTERIM === $type) {
                continue;
            }

            $weeklyHours = $contract->getWeeklyHours();
            if (null === $weeklyHours || $weeklyHours <= 35) {
                continue;
            }

            $fullMonthlyMinutes = ($weeklyHours - 35) * self::MINUTES_PER_WEEKLY_HOUR_PER_MONTH;
            $periodStart        = $period->getStartDate();
            $periodEnd          = $period->getEndDate();

            for ($month = 1; $month <= 12; ++$month) {
                $monthStart  = new DateTimeImmutable(sprintf('%04d-%02d-01', $civilYear, $month));
                $monthEnd    = $monthStart->modify('last day of this month');
                $daysInMonth = (int) $monthEnd->format('d');

                $overlapStart = $periodStart > $monthStart ? $periodStart : $monthStart;
                $overlapEnd   = (null !== $periodEnd && $periodEnd < $monthEnd) ? $periodEnd : $monthEnd;
                if ($overlapStart > $overlapEnd) {
                    continue;
                }

                $overlapDays = $overlapStart->diff($overlapEnd)->days + 1;
                $accumulated[$month] += $fullMonthlyMinutes * $overlapDays / $daysInMonth;
            }
        }

        $months = [];
        for ($month = 1; $month <= 12; ++$month) {
            $months[$month] = (int) round($accumulated[$month]);
        }

        return $months;
    }

    public function totalStructuralMinutes(Employee $employee, int $civilYear): int
    {
        return array_sum($this->monthlyStructuralMinutes($employee, $civilYear));
    }
}
