<?php

declare(strict_types=1);

namespace App\Scolarite\Domain\Model\Schedule;

use App\Scolarite\Domain\Exception\CreneauHoraireInvalideException;

use function explode;
use function preg_match;

/**
 * Value Object représentant un créneau horaire (heure début + heure fin).
 *
 * Format attendu : "HH:MM" (24h).
 * Contraintes : fin > début, durée minimum 5 minutes.
 */
final readonly class TimeSlot
{
    private const string TIME_PATTERN = '/^([01]\d|2[0-3]):[0-5]\d$/';
    private const int MINIMUM_DURATION_MINUTES = 5;

    public function __construct(
        public string $startTime,
        public string $endTime,
    ) {
        if (preg_match(self::TIME_PATTERN, $startTime) !== 1) {
            throw CreneauHoraireInvalideException::formatInvalide($startTime);
        }

        if (preg_match(self::TIME_PATTERN, $endTime) !== 1) {
            throw CreneauHoraireInvalideException::formatInvalide($endTime);
        }

        if ($endTime <= $startTime) {
            throw CreneauHoraireInvalideException::finAvantDebut($startTime, $endTime);
        }

        $duration = $this->computeDurationInMinutes($startTime, $endTime);

        if ($duration < self::MINIMUM_DURATION_MINUTES) {
            throw CreneauHoraireInvalideException::dureeTropCourte($duration);
        }
    }

    /**
     * Vérifie si ce créneau chevauche un autre créneau.
     *
     * Deux créneaux adjacents (fin de l'un = début de l'autre) ne se chevauchent pas.
     */
    public function overlaps(self $other): bool
    {
        return $this->startTime < $other->endTime && $other->startTime < $this->endTime;
    }

    public function equals(self $other): bool
    {
        return $this->startTime === $other->startTime
            && $this->endTime === $other->endTime;
    }

    public function durationInMinutes(): int
    {
        return $this->computeDurationInMinutes($this->startTime, $this->endTime);
    }

    private function computeDurationInMinutes(string $start, string $end): int
    {
        [$startHour, $startMin] = explode(':', $start);
        [$endHour, $endMin] = explode(':', $end);

        return ((int) $endHour * 60 + (int) $endMin) - ((int) $startHour * 60 + (int) $startMin);
    }
}
