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

use Ferienpass\CoreBundle\Entity\User;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Messenger\Envelope;
use Symfony\Component\Messenger\Middleware\MiddlewareInterface;
use Symfony\Component\Messenger\Middleware\StackInterface;
use Symfony\Component\Messenger\Stamp\ConsumedByWorkerStamp;
use Symfony\Contracts\Translation\LocaleAwareInterface;
use Symfony\Contracts\Translation\TranslatorInterface;

class LocaleMiddleware implements MiddlewareInterface
{
    public function __construct(
        private readonly TranslatorInterface $translator,
        private readonly Security $security,
        private readonly RequestStack $requestStack,
    ) {
    }

    public function handle(Envelope $envelope, StackInterface $stack): Envelope
    {
        if (!$this->translator instanceof LocaleAwareInterface) {
            return $stack->next()->handle($envelope, $stack);
        }

        $consumedByWorkerStamp = $envelope->last(ConsumedByWorkerStamp::class);
        $localeStamp = $envelope->last(LocaleStamp::class);

        if (null !== $consumedByWorkerStamp && $localeStamp instanceof LocaleStamp) {
            $initialLocale = $this->translator->getLocale();
            $this->translator->setLocale($localeStamp->getLocale());

            try {
                return $stack->next()->handle($envelope, $stack);
            } finally {
                $this->translator->setLocale($initialLocale);
            }
        }

        if (null === $localeStamp && null === $consumedByWorkerStamp) {
            $locale = $this->translator->getLocale();
            if (!$this->requestStack->getCurrentRequest() && ($user = $this->security->getUser()) && ($user instanceof User)) {
                $locale = $user->getLocale();
            }

            $envelope = $envelope->with(new LocaleStamp($locale));
        }

        return $stack->next()->handle($envelope, $stack);
    }
}
