<?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\Workflow;

use Ferienpass\CoreBundle\Entity\Debtor;
use Ferienpass\CoreBundle\Entity\Payment;
use Ferienpass\CoreBundle\Enum\PaymentStatus;
use Ferienpass\CoreBundle\Message\PaymentReceiptCreated;
use Ferienpass\CoreBundle\Payments\ReceiptNumberGenerator;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Workflow\Attribute\AsEnteredListener;
use Symfony\Component\Workflow\Event\EnteredEvent;

#[AsEnteredListener(workflow: 'payment', place: PaymentStatus::PAID)]
class PaymentPayTransactionListener
{
    public function __construct(private readonly ReceiptNumberGenerator $numberGenerator, private readonly MessageBusInterface $eventBus)
    {
    }

    public function __invoke(EnteredEvent $event): void
    {
        $payment = $event->getSubject();
        if (!$payment instanceof Payment) {
            throw new \RuntimeException('Unexpected event subject');
        }

        $context = $event->getContext();
        $payment->setReceiptNumber($this->numberGenerator->generate());

        $isReverse = $context['reverse'] ?? null;
        $payout = $context['payout'] ?? null;
        $notify = (bool) ($context['notify'] ?? true);

        if ($payment->getDebtor() instanceof Debtor) {
            if ('balance' === $payout) {
                $payment->createBookEntry((-1) * $payment->getTotalAmount(), type: 'manual');
            } else {
                $payment->createBookEntry();
            }
        }

        foreach ($payment->getItems() as $item) {
            if ($item->isDiscount()) {
                $payment->createBookEntry($item->getAmount());
                continue;
            }

            if (false !== $isReverse) {
                // The attendance is null when reversing a line whose attendance
                // was deleted after the original receipt was issued — there is
                // nothing left to mark (un)paid, but the money is still reversed.
                $item->getAttendance()?->setPaid(!$isReverse);
            }
        }

        $this->eventBus->dispatch(new PaymentReceiptCreated((string) $payment->getUuid(), $notify));
    }
}
