<?php

/*
 * 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\Bridge\Symfony\Bundle\EventListener;

use CpCreation\VitiCore\Locale\Model\Locale;
use CpCreation\VitiCore\Locale\Repository\LocaleRepository;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Routing\RequestContext;

#[AsEventListener(event: KernelEvents::REQUEST, method: 'onKernelRequest', priority: 10)]
final class LocaleListener
{
    /**
     * @var array<string, true>|null
     */
    private ?array $enabledLocales = null;

    public function __construct(
        private readonly string $defaultLocale = 'fr',
        private readonly ?RequestContext $requestContext = null,
        private readonly ?LocaleRepository $localeRepository = null,
    ) {}

    public function onKernelRequest(RequestEvent $event): void
    {
        if (!$event->isMainRequest()) {
            return;
        }

        $request = $event->getRequest();
        $routeLocale = $request->attributes->get('_locale');

        if (\is_string($routeLocale) && '' !== $routeLocale && !$this->isLocaleEnabled($routeLocale)) {
            throw new NotFoundHttpException(\sprintf('Locale "%s" is not enabled.', $routeLocale));
        }

        if ('setLocale' === $request->attributes->get('_route')) {
            $requestedLocale = $request->attributes->get('locale');

            if (\is_string($requestedLocale) && '' !== $requestedLocale && !$this->isLocaleEnabled($requestedLocale)) {
                throw new NotFoundHttpException(\sprintf('Locale "%s" is not enabled.', $requestedLocale));
            }
        }

        if ($request->attributes->getBoolean('_stateless')) {
            $this->requestContext?->setParameter('_locale', $request->getLocale());

            return;
        }

        $pathInfo = $request->getPathInfo();
        if ('/admincp' === $pathInfo || str_starts_with($pathInfo, '/admincp/')) {
            $request->setLocale($this->defaultLocale);

            if ($request->hasPreviousSession()) {
                $request->getSession()->set('_locale', $this->defaultLocale);
            }

            $this->requestContext?->setParameter('_locale', $this->defaultLocale);

            return;
        }

        if (!$request->hasPreviousSession()) {
            $this->requestContext?->setParameter('_locale', $request->getLocale());

            return;
        }

        $session = $request->getSession();

        if ($locale = $request->attributes->get('_locale')) {
            $session->set('_locale', $locale);
        } else {
            $request->setLocale(
                $session->get('_locale', $this->defaultLocale)
            );
        }

        $this->requestContext?->setParameter('_locale', $request->getLocale());
    }

    private function isLocaleEnabled(string $locale): bool
    {
        return isset($this->getEnabledLocales()[$locale]);
    }

    /**
     * @return array<string, true>
     */
    private function getEnabledLocales(): array
    {
        if (null !== $this->enabledLocales) {
            return $this->enabledLocales;
        }

        $enabledLocales = [
            $this->defaultLocale => true,
        ];

        foreach ($this->localeRepository?->findBy(['disabled' => 0]) ?? [] as $locale) {
            if (!$locale instanceof Locale) {
                continue;
            }

            $code = $locale->getLocale();
            if (\is_string($code) && '' !== $code) {
                $enabledLocales[$code] = true;
            }
        }

        return $this->enabledLocales = $enabledLocales;
    }
}
