<?php

declare(strict_types=1);

namespace App\Administration\Application\Command\AddPedagogicalDay;

use App\Administration\Domain\Model\SchoolCalendar\CalendarEntry;
use App\Administration\Domain\Model\SchoolCalendar\CalendarEntryId;
use App\Administration\Domain\Model\SchoolCalendar\CalendarEntryType;
use App\Administration\Domain\Model\SchoolCalendar\SchoolCalendar;
use App\Administration\Domain\Model\SchoolCalendar\SchoolCalendarRepository;
use App\Administration\Domain\Model\SchoolClass\AcademicYearId;
use App\Shared\Domain\Clock;
use App\Shared\Domain\Tenant\TenantId;
use DateTimeImmutable;
use InvalidArgumentException;

use function preg_match;

use Symfony\Component\Messenger\Attribute\AsMessageHandler;

/**
 * Ajoute une journée pédagogique au calendrier et déclenche la notification enseignants.
 */
#[AsMessageHandler(bus: 'command.bus')]
final readonly class AddPedagogicalDayHandler
{
    public function __construct(
        private SchoolCalendarRepository $calendarRepository,
        private Clock $clock,
    ) {
    }

    public function __invoke(AddPedagogicalDayCommand $command): SchoolCalendar
    {
        if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $command->date) !== 1) {
            throw new InvalidArgumentException('La date doit être au format YYYY-MM-DD.');
        }

        [$y, $m, $d] = explode('-', $command->date);
        if (!checkdate((int) $m, (int) $d, (int) $y)) {
            throw new InvalidArgumentException('La date n\'existe pas dans le calendrier.');
        }

        $tenantId = TenantId::fromString($command->tenantId);
        $academicYearId = AcademicYearId::fromString($command->academicYearId);
        $date = new DateTimeImmutable($command->date);

        $calendar = $this->calendarRepository->findByTenantAndYear($tenantId, $academicYearId)
            ?? SchoolCalendar::initialiser($tenantId, $academicYearId);

        $entry = new CalendarEntry(
            id: CalendarEntryId::generate(),
            type: CalendarEntryType::PEDAGOGICAL_DAY,
            startDate: $date,
            endDate: $date,
            label: $command->label,
            description: $command->description,
        );

        $calendar->ajouterJourneePedagogique($entry, $this->clock->now());

        $this->calendarRepository->save($calendar);

        return $calendar;
    }
}
