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

use Ferienpass\CoreBundle\Routing\AdminPath;
use Ferienpass\CoreBundle\Tenant\SurfaceContext;
use FOS\HttpCacheBundle\Configuration\InvalidatePath;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;

/**
 * Puts `#[InvalidatePath]` paths into the URL space of the domain the request
 * came in on.
 *
 * The attribute names an admin URL as the route collection spells it
 * (`/admin/teilnehmende/duplikate`), and FOSHttpCacheBundle turns that into a
 * PURGE matching the exact URL. On a domain that serves the admin at its root
 * the cached object is `/teilnehmende/duplikate` instead, so the PURGE would
 * match nothing and the page would stay stale for its full s-maxage.
 *
 * Priority 10 puts this ahead of FOSHttpCacheBundle's own
 * `InvalidationListener` (0), which reads the attribute off the request.
 */
#[AsEventListener(event: KernelEvents::RESPONSE, priority: 10)]
class AdminInvalidatePathListener
{
    public function __construct(private readonly SurfaceContext $surfaces)
    {
    }

    public function __invoke(ResponseEvent $event): void
    {
        if (!$this->surfaces->adminAtRoot()) {
            return;
        }

        $configurations = $event->getRequest()->attributes->get('_invalidate_path');
        if (!\is_array($configurations)) {
            return;
        }

        foreach ($configurations as $configuration) {
            if (!$configuration instanceof InvalidatePath) {
                continue;
            }

            $configuration->setPaths(array_map(
                static fn (string $path) => AdminPath::isAdmin($path) ? AdminPath::strip($path) : $path,
                $configuration->getPaths(),
            ));
        }
    }
}
