<?php

/*
 * This file is part of the Serenity 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 Serenity\CoreBundle\Slug\EventListener;

use Doctrine\ORM\EntityManagerInterface;
use Serenity\CoreBundle\Slug\Entity\SlugHistory;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;

#[AsEventListener(event: KernelEvents::EXCEPTION, priority: 0)]
readonly class RedirectOldSlugListener
{
    public function __construct(
        private EntityManagerInterface $em,
        private UrlGeneratorInterface $urlGenerator,
    ) {
    }

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

        $throwable = $event->getThrowable();
        if (!$throwable instanceof NotFoundHttpException) {
            return;
        }

        $request = $event->getRequest();

        // On ne traite que les routes avec param {slug}
        $routeParams = (array) $request->attributes->get('_route_params', []);
        $slug = $routeParams['slug'] ?? null;

        /** @var class-string<object> $entityClass */
        $entityClass = $request->attributes->get('entity');

        if (!\is_string($slug) || '' === $slug || !\is_string($entityClass) || '' === $entityClass) {
            return;
        }

        /** @var SlugHistory|null $history */
        $history = $this->em->getRepository(SlugHistory::class)->findOneBy([
            'entityClass' => $entityClass,
            'oldSlug' => $slug,
        ]);

        if (!$history) {
            return;
        }

        $entityId = $history->entityId;
        $code = $history->code;

        $entity = $this->em->find($entityClass, $entityId);
        if (!$entity || !method_exists($entity, 'getSlug')) {
            return;
        }

        $currentSlug = $entity->getSlug();
        if (!\is_string($currentSlug) || '' === $currentSlug || $currentSlug === $slug) {
            return;
        }

        $route = $request->attributes->get('_route');
        if (!\is_string($route) || '' === $route) {
            return;
        }

        $routeParams['slug'] = $currentSlug;

        $url = $this->urlGenerator->generate(
            $route,
            $routeParams,
            UrlGeneratorInterface::ABSOLUTE_URL
        );

        $statusCode = ($code >= 300 && $code < 400) ? $code : 301;

        $event->setResponse(new RedirectResponse($url, $statusCode));
    }
}
