<?php

declare(strict_types=1);

namespace App\Scolarite\Application\Query\GetBlockedDates;

use App\Administration\Domain\Model\SchoolCalendar\SchoolCalendarRepository;
use App\Administration\Domain\Model\SchoolClass\AcademicYearId;
use App\Shared\Domain\Tenant\TenantId;
use DateInterval;
use DateTimeImmutable;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;

/**
 * Retourne les dates bloquées (jours fériés, vacances, journées pédagogiques, weekends)
 * pour une plage de dates donnée.
 *
 * Utilisé par le frontend pour griser les jours non modifiables dans la grille EDT.
 */
#[AsMessageHandler(bus: 'query.bus')]
final readonly class GetBlockedDatesHandler
{
    public function __construct(
        private SchoolCalendarRepository $calendarRepository,
    ) {
    }

    /** @return array<BlockedDateDto> */
    public function __invoke(GetBlockedDatesQuery $query): array
    {
        $tenantId = TenantId::fromString($query->tenantId);
        $academicYearId = AcademicYearId::fromString($query->academicYearId);

        $calendar = $this->calendarRepository->findByTenantAndYear($tenantId, $academicYearId);

        $startDate = new DateTimeImmutable($query->startDate);
        $endDate = new DateTimeImmutable($query->endDate);
        $oneDay = new DateInterval('P1D');

        $blockedDates = [];
        $current = $startDate;

        while ($current <= $endDate) {
            $dayOfWeek = (int) $current->format('N');
            $dateStr = $current->format('Y-m-d');

            if ($dayOfWeek >= 6) {
                $blockedDates[] = new BlockedDateDto(
                    date: $dateStr,
                    reason: $dayOfWeek === 6 ? 'Samedi' : 'Dimanche',
                    type: 'weekend',
                );
            } elseif ($calendar !== null) {
                $entry = $calendar->trouverEntreePourDate($current);

                if ($entry !== null) {
                    $blockedDates[] = new BlockedDateDto(
                        date: $dateStr,
                        reason: $entry->label,
                        type: $entry->type->value,
                    );
                }
            }

            $current = $current->add($oneDay);
        }

        return $blockedDates;
    }
}
