<?php

declare(strict_types=1);

/*
 * This file is part of the VITICORE2 package.
 *
 * (c) CP Creation <web@cpcreation.fr>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace CpCreation\VitiCore\Commerce\Catalog\Outbox\Message;

use CpCreation\VitiCore\Commerce\Catalog\Configuration\CatalogWebhookEndpointResolver;
use CpCreation\VitiCore\Commerce\Catalog\Repository\CatalogChangeRepository;
use Doctrine\ORM\EntityManagerInterface;
use Psr\Log\LoggerInterface;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use Symfony\Component\Messenger\MessageBusInterface;

#[AsMessageHandler]
final readonly class DispatchCatalogChangesMessageHandler
{
    private const string STALE_QUEUED_INTERVAL = '15 minutes';

    public function __construct(
        private CatalogWebhookEndpointResolver $webhookEndpointResolver,
        private CatalogChangeRepository $repository,
        private EntityManagerInterface $entityManager,
        private MessageBusInterface $messageBus,
        private ?LoggerInterface $logger = null,
    ) {}

    public function __invoke(DispatchCatalogChangesMessage $message): void
    {
        if (!$this->webhookEndpointResolver->isReady()) {
            return;
        }

        $queuedAt = new \DateTimeImmutable();
        $staleQueuedBefore = $queuedAt->sub(new \DateInterval('PT15M'));
        $changes = $this->repository->findReadyForDelivery($staleQueuedBefore, $message->limit);

        if ([] === $changes) {
            return;
        }

        foreach ($changes as $change) {
            $change->markQueued($queuedAt);
        }

        // Le claim est durable avant l'envoi dans Messenger. Un crash entre les
        // deux est récupéré par la fenêtre stale ci-dessus.
        $this->entityManager->flush();

        foreach ($changes as $change) {
            $this->messageBus->dispatch(new DeliverCatalogChangeMessage($change->getEventId()->toString()));
        }

        $this->logger?->info('Notifications Commerce mises en file.', [
            'count' => \count($changes),
            'stale_after' => self::STALE_QUEUED_INTERVAL,
        ]);
    }
}
