<?php

declare(strict_types=1);

/*
 * This file is part of the Ferienpass package.
 *
 * (c) Richard Henkenjohann <richard@ferienpass.online>
 *
 * For more information visit the project website <https://ferienpass.online>
 * or the documentation under <https://docs.ferienpass.online>.
 */

namespace Ferienpass\CoreBundle\MessageHandler;

use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Criteria;
use Doctrine\Common\Collections\Order;
use Ferienpass\CoreBundle\ApplicationSystem\ApplicationSystems;
use Ferienpass\CoreBundle\ApplicationSystem\LotApplicationSystem;
use Ferienpass\CoreBundle\Entity\Attendance;
use Ferienpass\CoreBundle\Entity\Edition;
use Ferienpass\CoreBundle\Entity\Participant\ParticipantInterface;
use Ferienpass\CoreBundle\Message\UpdateParticipantPriorities as UpdatePrioritiesCommand;
use Ferienpass\CoreBundle\Repository\EditionRepository;
use Ferienpass\CoreBundle\Repository\ParticipantRepositoryInterface;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use Symfony\Component\Uid\Uuid;

#[AsMessageHandler(bus: 'command.bus')]
class UpdateParticipantPriorities
{
    public function __construct(private readonly ParticipantRepositoryInterface $participants, private readonly EditionRepository $editions, private readonly ApplicationSystems $applicationSystems)
    {
    }

    public function __invoke(UpdatePrioritiesCommand $command, Uuid $uuid): void
    {
        $participant = $this->participants->findOneBy(['uuid' => $command->getParticipantId()]);
        if (!$participant instanceof ParticipantInterface) {
            return;
        }
        $edition = $this->editions->findOneBy(['uuid' => $command->getEditionId()]);
        if (!$edition instanceof Edition) {
            return;
        }

        $applicationSystem = $this->applicationSystems->findApplicationSystem($edition);
        if (!$applicationSystem instanceof LotApplicationSystem) {
            return;
        }

        $maxPriority = $applicationSystem->getTask()->getMaxApplications();

        /** @var ArrayCollection|Attendance[] $attendances */
        $attendances = $participant->getAttendancesWaiting()
            ->matching(Criteria::create()->orderBy(['userPriority' => Order::Ascending]))
        ;

        if ($attendances->isEmpty()) {
            return;
        }

        $maxPriority ??= $attendances->count() + 1;

        $priority = 1;
        foreach ($attendances as $attendance) {
            if ($attendance->isHidden()) {
                continue;
            }

            if ($priority > $maxPriority) {
                break;
            }

            $attendance->setUserPriority($priority);
            ++$priority;
        }
    }
}
