<?php
declare(strict_types=1);

namespace App\Core;

use App\Security\RouteAuthorization;
use App\Security\RequestSecurity;
use App\Security\ZeroTrustEngine;

final class SecurityKernel
{
    /** @var list<string> */
    private const PUBLIC_GET = ['/login', '/consentement-public'];
    /** @var list<string> */
    private const PUBLIC_POST = ['/login', '/consentement-public/signature', '/api/axiom'];

    public static function enforce(string $method, string $path, array $policy = []): void
    {
        $method = strtoupper($method);
        $path = self::normalize($path);
        RequestSecurity::enforce($method, $path);

        $isPublic = ($policy['public'] ?? false) === true || self::isPublic($method, $path);
        if (!$isPublic) {
            Auth::requireLogin();
            TenantContext::bootFromAuthenticatedUser();
            ZeroTrustEngine::enforce($method, $path, $policy);
            RouteAuthorization::authorize($policy);
        }

        if (in_array($method, ['POST', 'PUT', 'PATCH', 'DELETE'], true)
            && $path !== '/api/axiom'
            && $path !== '/consentement-public/signature') {
            Csrf::verify($_POST['_csrf'] ?? ($_SERVER['HTTP_X_CSRF_TOKEN'] ?? null));
        }

        if (!in_array($method, ['GET', 'HEAD', 'POST', 'PUT', 'PATCH', 'DELETE'], true)) {
            http_response_code(405);
            header('Allow: GET, HEAD, POST, PUT, PATCH, DELETE');
            exit('Méthode non autorisée.');
        }

        if ($method !== 'GET' && $method !== 'HEAD') {
            header('Cache-Control: no-store, private');
        }
    }

    private static function isPublic(string $method, string $path): bool
    {
        return $method === 'GET'
            ? in_array($path, self::PUBLIC_GET, true)
            : ($method === 'POST' && in_array($path, self::PUBLIC_POST, true));
    }

    private static function normalize(string $path): string
    {
        $path = str_replace('/public', '', $path) ?: '/';
        $path = '/' . trim($path, '/');
        return $path === '/' ? '/' : rtrim($path, '/');
    }
}
