<?php

declare(strict_types=1);

namespace App\Shared\Infrastructure\Tenant;

use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Event\RequestEvent;
use Symfony\Component\HttpKernel\KernelEvents;

final readonly class TenantMiddleware implements EventSubscriberInterface
{
    public function __construct(
        private TenantResolver $resolver,
        private TenantContext $context,
    ) {
    }

    public static function getSubscribedEvents(): array
    {
        return [
            KernelEvents::REQUEST => ['onKernelRequest', 256], // High priority - run early
            KernelEvents::TERMINATE => 'onKernelTerminate',
        ];
    }

    private const array PUBLIC_PATHS = [
        '/api/docs',
        '/api/docs.json',
        '/api/docs.jsonld',
        '/api/contexts',
        '/api/activation-tokens',
        '/api/activate',
        '/api/login',
        '/api/password',
        '/api/token',
        '/_profiler',
        '/_wdt',
        '/_error',
        '/health',
        '/metrics',
    ];

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

        $request = $event->getRequest();
        $path = $request->getPathInfo();
        $host = $request->getHost();

        // Check if this is a public path (docs, profiler, login, etc.)
        $isPublicPath = false;
        foreach (self::PUBLIC_PATHS as $publicPath) {
            if (str_starts_with($path, $publicPath)) {
                $isPublicPath = true;
                break;
            }
        }

        try {
            $config = $this->resolver->resolve($host);
            $this->context->setCurrentTenant($config);

            // Store tenant config in request for easy access
            $request->attributes->set('_tenant', $config);
        } catch (TenantNotFoundException) {
            // For public paths, allow requests without tenant context (metrics will show "none")
            if ($isPublicPath) {
                return;
            }

            // For protected paths, return 404 with generic message - DO NOT reveal tenant 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);
        }
    }

    public function onKernelTerminate(): void
    {
        $this->context->clear();
    }
}
