<?php

declare(strict_types=1);

namespace App\Service\WorkHours;

use App\Entity\WorkHour;

/**
 * Calcul des minutes travaillees de nuit (fenetre 21h->6h).
 *
 * Fenetres en minutes depuis 00:00 : [0,360] (00:00-06:00) et [1260,1440]
 * (21:00-24:00). On projette sur J+1 pour les shifts qui traversent minuit.
 * Source de verite unique partagee par les ecrans Heures et les exports.
 */
final readonly class NightHoursCalculator
{
    /**
     * Minutes de nuit d'un WorkHour. Conducteurs : champ manuel nightHoursMinutes.
     * Non-conducteurs : somme calculee depuis les plages matin/apres-midi/soir.
     */
    public function nightMinutesForWorkHour(WorkHour $workHour, bool $isDriver): int
    {
        if ($isDriver) {
            return $workHour->getNightHoursMinutes() ?? 0;
        }

        return $this->nightMinutesFromRanges($workHour);
    }

    public function nightMinutesFromRanges(WorkHour $workHour): int
    {
        $ranges = [
            [$workHour->getMorningFrom(), $workHour->getMorningTo()],
            [$workHour->getAfternoonFrom(), $workHour->getAfternoonTo()],
            [$workHour->getEveningFrom(), $workHour->getEveningTo()],
        ];

        $total = 0;
        foreach ($ranges as [$from, $to]) {
            $total += $this->nightIntervalMinutes($from, $to);
        }

        return $total;
    }

    public function nightIntervalMinutes(?string $from, ?string $to): int
    {
        $interval = $this->resolveInterval($from, $to);
        if (null === $interval) {
            return 0;
        }

        [$start, $end] = $interval;
        $windows       = [[0, 360], [1260, 1440]];
        $total         = 0;

        for ($dayOffset = 0; $dayOffset <= 1; ++$dayOffset) {
            $shift = $dayOffset * 1440;
            foreach ($windows as [$windowStart, $windowEnd]) {
                $total += $this->overlap($start, $end, $windowStart + $shift, $windowEnd + $shift);
            }
        }

        return $total;
    }

    /**
     * @return null|array{int, int}
     */
    private function resolveInterval(?string $from, ?string $to): ?array
    {
        $fromMinutes = $this->toMinutes($from);
        $toMinutes   = $this->toMinutes($to);
        if (null === $fromMinutes || null === $toMinutes) {
            return null;
        }

        $end = $toMinutes <= $fromMinutes ? $toMinutes + 1440 : $toMinutes;

        return [$fromMinutes, $end];
    }

    private function toMinutes(?string $time): ?int
    {
        if (null === $time || '' === $time) {
            return null;
        }

        [$hours, $minutes] = array_map('intval', explode(':', $time));

        return ($hours * 60) + $minutes;
    }

    private function overlap(int $startA, int $endA, int $startB, int $endB): int
    {
        $start = max($startA, $startB);
        $end   = min($endA, $endB);

        return max(0, $end - $start);
    }
}
