<?php

namespace App\Shared\EventSubscriber;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;

/**
 * Adds a Content-Security-Policy to the admin SPA responses (/admin/*).
 * The /api/* surface already sends `default-src 'none'`; the SPA had none, so a
 * DOM-injected script had no second line of defence. Scoped to /admin only to
 * avoid breaking the strict API CSP.
 */
final class AdminCspSubscriber implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [KernelEvents::RESPONSE => 'onResponse'];
    }

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

        if (!str_starts_with($event->getRequest()->getPathInfo(), '/admin')) {
            return;
        }

        $response = $event->getResponse();
        if ($response->headers->has('Content-Security-Policy')) {
            return;
        }

        $response->headers->set(
            'Content-Security-Policy',
            "default-src 'self'; "
            . "script-src 'self'; "
            . "worker-src 'self' blob:; "            // ALTCHA proof-of-work solver runs in blob: Web Workers
            . "style-src 'self' 'unsafe-inline'; "   // Tailwind / CKEditor inline styles
            // OpenStreetMap tiles + unpkg Leaflet marker icons render the clinic-location map
            . "img-src 'self' data: blob: https://*.tile.openstreetmap.org https://unpkg.com; "
            . "font-src 'self' data:; "
            // nominatim geocoding + OSM tile fetches for the clinic-location map
            . "connect-src 'self' https://nominatim.openstreetmap.org https://*.tile.openstreetmap.org; "
            . "frame-ancestors 'none'; "
            . "base-uri 'self'; "
            . "object-src 'none'"
        );
    }
}
