<?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\EventListener\Doctrine\Attendance;

use Doctrine\Bundle\DoctrineBundle\Attribute\AsEntityListener;
use Doctrine\ORM\Event\PreUpdateEventArgs;
use Doctrine\ORM\Events;
use Ferienpass\CoreBundle\ApplicationSystem\ApplicationSystemInterface;
use Ferienpass\CoreBundle\Entity\Attendance;
use Ferienpass\CoreBundle\Entity\ParticipantLog;
use Ferienpass\CoreBundle\Enum\AttendanceStatus;
use Ferienpass\CoreBundle\Enum\AttendanceTransition;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\Workflow\Transition;

#[AsEntityListener(event: Events::prePersist, entity: Attendance::class)]
#[AsEntityListener(event: Events::preUpdate, entity: Attendance::class)]
class AttendanceLogListener
{
    public function __construct(private readonly Security $security)
    {
    }

    public function prePersist(Attendance $attendance): void
    {
        $byLot = $attendance->isLottingActor();

        $attendance->getActivity()->add(new ParticipantLog(
            $attendance->getParticipant(),
            $byLot ? null : $this->security->getUser(),
            $attendance,
            transition: new Transition(AttendanceTransition::CREATE, [], [(string) $attendance->getStatus()]),
            applicationSystem: $byLot ? ApplicationSystemInterface::LOT : null,
            decisionReason: $attendance->getLottingDecisionReason(),
        ));
    }

    public function preUpdate(Attendance $attendance, PreUpdateEventArgs $eventArgs): void
    {
        if (!$eventArgs->hasChangedField('status') || null === ($status = $eventArgs->getNewValue('status'))) {
            return;
        }

        $transitionName = match ($status) {
            AttendanceStatus::CONFIRMED => AttendanceTransition::CONFIRM,
            AttendanceStatus::WAITLISTED => AttendanceTransition::WAITLIST,
            AttendanceStatus::WITHDRAWN => AttendanceTransition::WITHDRAW,
            AttendanceStatus::WAITING => AttendanceTransition::RESET,
            AttendanceStatus::REJECTED => AttendanceTransition::REJECT,
            AttendanceStatus::UNFULFILLED => AttendanceTransition::UNFULFILL,
            default => null,
        };

        if (null === $transitionName) {
            return;
        }

        $byLot = $attendance->isLottingActor();

        $oldStatus = (string) $eventArgs->getOldValue('status');
        $from = '' === $oldStatus ? [] : [$oldStatus];

        $attendance->getActivity()->add(new ParticipantLog(
            $attendance->getParticipant(),
            $byLot ? null : $this->security->getUser(),
            $attendance,
            transition: new Transition($transitionName, $from, $status),
            applicationSystem: $byLot ? ApplicationSystemInterface::LOT : null,
            decisionReason: $attendance->getLottingDecisionReason(),
        ));
    }
}
