<?php

declare(strict_types=1);

namespace App\Scolarite\Application\Command\LinkCompetenciesToEvaluation;

use App\Administration\Domain\Model\User\UserId;
use App\Scolarite\Domain\Exception\NonProprietaireDeLEvaluationException;
use App\Scolarite\Domain\Model\Competency\CompetencyEvaluation;
use App\Scolarite\Domain\Model\Competency\CompetencyId;
use App\Scolarite\Domain\Model\Evaluation\EvaluationId;
use App\Scolarite\Domain\Repository\CompetencyEvaluationRepository;
use App\Scolarite\Domain\Repository\CompetencyRepository;
use App\Scolarite\Domain\Repository\EvaluationRepository;
use App\Shared\Domain\Tenant\TenantId;
use DomainException;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;

#[AsMessageHandler(bus: 'command.bus')]
final readonly class LinkCompetenciesToEvaluationHandler
{
    public function __construct(
        private EvaluationRepository $evaluationRepository,
        private CompetencyRepository $competencyRepository,
        private CompetencyEvaluationRepository $competencyEvaluationRepository,
    ) {
    }

    /** @return array<CompetencyEvaluation> */
    public function __invoke(LinkCompetenciesToEvaluationCommand $command): array
    {
        $tenantId = TenantId::fromString($command->tenantId);
        $evaluationId = EvaluationId::fromString($command->evaluationId);
        $teacherId = UserId::fromString($command->teacherId);

        $evaluation = $this->evaluationRepository->get($evaluationId, $tenantId);

        if ((string) $evaluation->teacherId !== (string) $teacherId) {
            throw NonProprietaireDeLEvaluationException::withId($evaluationId);
        }

        $existingCes = $this->competencyEvaluationRepository->findByEvaluation($evaluationId);
        $existingByCompetency = [];
        foreach ($existingCes as $existing) {
            $existingByCompetency[(string) $existing->competencyId] = $existing;
        }

        $linked = [];

        foreach ($command->competencyIds as $competencyIdStr) {
            $competencyId = CompetencyId::fromString($competencyIdStr);

            // Skip already linked competencies
            if (isset($existingByCompetency[$competencyIdStr])) {
                $linked[] = $existingByCompetency[$competencyIdStr];
                continue;
            }

            $competency = $this->competencyRepository->findById($competencyId, $tenantId);
            if ($competency === null) {
                throw new DomainException('Compétence non trouvée : ' . $competencyIdStr);
            }

            $ce = CompetencyEvaluation::creer(
                evaluationId: $evaluationId,
                competencyId: $competencyId,
            );

            $this->competencyEvaluationRepository->save($ce);
            $linked[] = $ce;
        }

        return $linked;
    }
}
