<?php

declare(strict_types=1);

namespace App\Administration\Application\Command\ConfigurePeriods;

use App\Administration\Domain\Event\PeriodesConfigurees;
use App\Administration\Domain\Exception\PeriodesDejaConfigureesException;
use App\Administration\Domain\Model\AcademicYear\DefaultPeriods;
use App\Administration\Domain\Model\AcademicYear\PeriodConfiguration;
use App\Administration\Domain\Model\AcademicYear\PeriodType;
use App\Administration\Domain\Model\SchoolClass\AcademicYearId;
use App\Administration\Domain\Repository\PeriodConfigurationRepository;
use App\Shared\Domain\Clock;
use App\Shared\Domain\Tenant\TenantId;

use function count;

use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use Symfony\Component\Messenger\MessageBusInterface;

/**
 * Handler pour configurer les périodes d'une année scolaire.
 *
 * Crée les périodes par défaut (trimestres ou semestres) pour l'année donnée.
 * Refuse si des périodes existent déjà.
 */
#[AsMessageHandler(bus: 'command.bus')]
final readonly class ConfigurePeriodsHandler
{
    public function __construct(
        private PeriodConfigurationRepository $repository,
        private Clock $clock,
        private MessageBusInterface $eventBus,
    ) {
    }

    public function __invoke(ConfigurePeriodsCommand $command): PeriodConfiguration
    {
        $tenantId = TenantId::fromString($command->tenantId);
        $academicYearId = AcademicYearId::fromString($command->academicYearId);
        $periodType = PeriodType::from($command->periodType);

        $existing = $this->repository->findByAcademicYear($tenantId, $academicYearId);
        if ($existing !== null) {
            throw PeriodesDejaConfigureesException::pourAnnee($command->academicYearId);
        }

        $configuration = DefaultPeriods::forType($periodType, $command->startYear);

        $this->repository->save($tenantId, $academicYearId, $configuration);

        $this->eventBus->dispatch(new PeriodesConfigurees(
            academicYearId: $academicYearId,
            tenantId: $tenantId,
            periodType: $periodType,
            periodCount: count($configuration->periods),
            occurredOn: $this->clock->now(),
        ));

        return $configuration;
    }
}
