<?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\AdminBundle\EventListener;

use Ferienpass\CoreBundle\Settings\MailConfigManager;
use Symfony\Bundle\SecurityBundle\Security;
use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\HttpFoundation\AcceptHeader;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
use Twig\Environment;

#[AsEventListener(priority: -50)]
class PrettyErrorScreenListener
{
    public function __construct(
        #[Autowire(param: 'kernel.debug')]
        private readonly bool $isDebug,
        private readonly Environment $twig,
        private readonly MailConfigManager $mailConfigManager,
        private readonly Security $security,
    ) {
    }

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

        $request = $event->getRequest();

        // Admin routes are prefixed with /admin. Regex matches /admin and /{_locale}/admin.
        if (!preg_match('#^/(?:[a-z]{2,3}/)?admin(?:/|$)#', $request->getPathInfo())) {
            return;
        }

        if ('html' !== $request->getRequestFormat()) {
            return;
        }

        if (!AcceptHeader::fromString($request->headers->get('Accept'))->has('text/html')) {
            return;
        }

        $exception = $event->getThrowable();
        $statusCode = $exception instanceof HttpExceptionInterface ? $exception->getStatusCode() : 500;

        // 403 is handled in security.yaml
        if (!\in_array($statusCode, [404, 500], true)) {
            return;
        }

        $template = \sprintf('@FerienpassAdmin/page/error/%d.html.twig', $statusCode);

        try {
            $response = new Response($this->twig->render($template, [
                'adminEmail' => $this->mailConfigManager->getAdminEmail(),
                'adminEmailName' => $this->mailConfigManager->getAdminEmailName(),
                'statusCode' => $statusCode,
                'exception' => $exception,
                'isLoggedIn' => null !== $this->security->getUser(),
            ]), $statusCode);

            $event->setResponse($response);
        } catch (\Throwable) {
            // Fallback if rendering fails
        }
    }
}
