<?php

namespace App\Shared\Event;

use App\Shared\Event\Entity\DomainEventLog;
use Doctrine\ORM\EntityManagerInterface;

/**
 * تنها نقطهٔ ثبت رویداد دامنه.
 *
 * `record()` عمداً **flush نمی‌کند**: ردیف رویداد باید در همان تراکنشی commit شود که
 * خودِ تغییر را انجام می‌دهد. اگر اینجا flush می‌کردیم، rollbackِ تراکنش اصلی رویدادی
 * را جا می‌گذاشت که هرگز اتفاق نیفتاده.
 */
final class DomainEventPublisher
{
    public function __construct(
        private readonly EntityManagerInterface $em,
    ) {}

    /**
     * @param array<string, mixed> $payload فقط uuid و اسکالر
     */
    public function record(string $entityType, int $entityId, string $name, array $payload, ?int $occurredAt = null): DomainEventLog
    {
        if (!in_array($name, DomainEvents::ALL, true)) {
            throw new \InvalidArgumentException(sprintf('Unknown domain event "%s".', $name));
        }

        $event = new DomainEventLog($entityType, $entityId, $name, $payload, $occurredAt);

        $this->em->persist($event);

        return $event;
    }

    /**
     * ثبت + flush — برای جاهایی که فراخوان تراکنش باز ندارد.
     *
     * @param array<string, mixed> $payload
     */
    public function recordAndFlush(string $entityType, int $entityId, string $name, array $payload, ?int $occurredAt = null): DomainEventLog
    {
        $event = $this->record($entityType, $entityId, $name, $payload, $occurredAt);
        $this->em->flush();

        return $event;
    }
}
