<?php

declare(strict_types=1);

namespace App\Administration\Application\Command\ConfigureGradingMode;

use App\Administration\Application\Port\GradeExistenceChecker;
use App\Administration\Domain\Model\GradingConfiguration\GradingMode;
use App\Administration\Domain\Model\GradingConfiguration\SchoolGradingConfiguration;
use App\Administration\Domain\Model\SchoolClass\AcademicYearId;
use App\Administration\Domain\Model\SchoolClass\SchoolId;
use App\Administration\Domain\Repository\GradingConfigurationRepository;
use App\Shared\Domain\Clock;
use App\Shared\Domain\Tenant\TenantId;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;

/**
 * Handler pour configurer le mode de notation d'un établissement.
 *
 * Crée une nouvelle configuration si aucune n'existe pour l'année scolaire,
 * ou modifie la configuration existante si aucune note n'a été saisie.
 */
#[AsMessageHandler(bus: 'command.bus')]
final readonly class ConfigureGradingModeHandler
{
    public function __construct(
        private GradingConfigurationRepository $repository,
        private GradeExistenceChecker $gradeExistenceChecker,
        private Clock $clock,
    ) {
    }

    public function __invoke(ConfigureGradingModeCommand $command): SchoolGradingConfiguration
    {
        $tenantId = TenantId::fromString($command->tenantId);
        $schoolId = SchoolId::fromString($command->schoolId);
        $academicYearId = AcademicYearId::fromString($command->academicYearId);
        $mode = GradingMode::from($command->gradingMode);
        $now = $this->clock->now();

        $existing = $this->repository->findBySchoolAndYear($tenantId, $schoolId, $academicYearId);
        $hasGrades = $this->gradeExistenceChecker->hasGradesForYear($tenantId, $schoolId, $academicYearId);

        if ($existing === null) {
            $configuration = SchoolGradingConfiguration::configurer(
                tenantId: $tenantId,
                schoolId: $schoolId,
                academicYearId: $academicYearId,
                mode: $mode,
                hasExistingGrades: $hasGrades,
                configuredAt: $now,
            );
        } else {
            $existing->changerMode(
                nouveauMode: $mode,
                hasExistingGrades: $hasGrades,
                at: $now,
            );

            $configuration = $existing;
        }

        $this->repository->save($configuration);

        return $configuration;
    }
}
