<?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 Ferienpass\CoreBundle\Export\Offer\OffersExportInterface;
use Ferienpass\CoreBundle\Message\ExportFinished;
use Ferienpass\CoreBundle\Message\ExportOffers as ExportOffersCommand;
use Ferienpass\CoreBundle\Repository\OfferRepositoryInterface;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\DependencyInjection\Attribute\AutowireLocator;
use Symfony\Component\DependencyInjection\ServiceLocator;
use Symfony\Component\Messenger\Attribute\AsMessageHandler;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\MessageBusInterface;
use Symfony\Component\Messenger\Stamp\DispatchAfterCurrentBusStamp;

#[AsMessageHandler(bus: 'command.bus')]
class ExportOffers
{
    public function __construct(private readonly OfferRepositoryInterface $offers, #[AutowireLocator(OffersExportInterface::class, indexAttribute: 'name', defaultIndexMethod: 'getName')] private readonly ServiceLocator $exports, #[Autowire('%kernel.project_dir%/%contao.upload_path%/Export')] private readonly string $destination, private readonly MessageBusInterface $eventBus)
    {
    }

    public function __invoke(ExportOffersCommand $command): void
    {
        $offers = $this->offers->findBy(['uuid' => $command->getOfferUuids()]);
        if (empty($offers)) {
            return;
        }

        // Retain ordered ids
        $order = array_flip(array_values($command->getOfferUuids()));
        usort($offers, static fn ($a, $b) => ($order[(string) $a->getUuid()] ?? \PHP_INT_MAX) <=> ($order[(string) $b->getUuid()] ?? \PHP_INT_MAX));

        /** @var OffersExportInterface $exporter */
        $exporter = $this->exports->get($command->getExporter());

        $file = $exporter->generate($offers);

        $event = new ExportFinished($file, $command->getRecipient());
        $this->eventBus->dispatch(
            new Envelope($event)
                ->with(new DispatchAfterCurrentBusStamp())
        );
    }
}
