<?php

declare(strict_types=1);

namespace App\Shared\Infrastructure\Security;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\ExceptionEvent;
use Symfony\Component\HttpKernel\KernelEvents;
use Symfony\Component\Security\Core\Exception\AccessDeniedException;

/**
 * Converts AccessDeniedException for TenantAware resources to 404 responses.
 *
 * CRITICAL SECURITY: This prevents information leakage about resource existence.
 * When a user is denied access to a resource in another tenant, we return 404
 * instead of 403 to avoid revealing that the resource exists.
 */
final readonly class TenantAccessDeniedHandler implements EventSubscriberInterface
{
    public static function getSubscribedEvents(): array
    {
        return [
            KernelEvents::EXCEPTION => ['onKernelException', 2], // Higher priority than default
        ];
    }

    public function onKernelException(ExceptionEvent $event): void
    {
        $exception = $event->getThrowable();

        if (!$exception instanceof AccessDeniedException) {
            return;
        }

        // Check if this is a TenantAware resource denial
        // The subject is stored in the exception's attributes
        $subject = $exception->getSubject();

        if ($subject instanceof TenantAwareInterface) {
            // Convert to 404 to hide resource existence
            $response = new JsonResponse(
                [
                    'status' => Response::HTTP_NOT_FOUND,
                    'message' => 'Resource not found',
                    'type' => 'https://classeo.fr/errors/resource-not-found',
                ],
                Response::HTTP_NOT_FOUND
            );

            $event->setResponse($response);
        }
    }
}
