<?php

declare(strict_types=1);

namespace ApiModel\Infrastructure\Security;

use ApiModel\Shared\Http\ErrorResponse;

final class GatewaySecurity
{
    public static function enforceSecurityHeaders(): void
    {
        header('X-Frame-Options: DENY');
        header('X-Content-Type-Options: nosniff');
        header('Strict-Transport-Security: max-age=31536000; includeSubDomains');
        header('Referrer-Policy: no-referrer');
        header('Permissions-Policy: geolocation=(), camera=(), microphone=()');
        header('Cross-Origin-Opener-Policy: same-origin');
        header('Cross-Origin-Resource-Policy: same-site');
    }

    public static function attachRequestId(): string
    {
        $incoming = trim((string) ($_SERVER['HTTP_X_REQUEST_ID'] ?? ''));
        $requestId = $incoming !== '' ? preg_replace('/[^a-zA-Z0-9._-]/', '', $incoming) : self::generateRequestId();
        if ($requestId === null || $requestId === '') {
            $requestId = self::generateRequestId();
        }

        header('X-Request-Id: ' . $requestId);

        return $requestId;
    }

    public static function guardJsonBody(): void
    {
        $method = strtoupper((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET'));
        if (! in_array($method, ['POST', 'PATCH', 'PUT'], true)) {
            return;
        }

        $contentType = strtolower((string) ($_SERVER['CONTENT_TYPE'] ?? ''));
        if ($contentType === '') {
            return;
        }

        if (! str_contains($contentType, 'application/json') && ! str_contains($contentType, 'multipart/form-data')) {
            self::deny(415, 'Content-Type no soportado. Usa application/json.');
        }
    }

    public static function throttleByIp(string $bucket, int $max, int $windowSeconds): void
    {
        IpRateThrottle::enforce($bucket, $max, $windowSeconds);
    }

    private static function generateRequestId(): string
    {
        return bin2hex(random_bytes(16));
    }

    private static function deny(int $status, string $message): void
    {
        http_response_code($status);
        header('Content-Type: application/json; charset=utf-8');
        $payload = ErrorResponse::payload(
            $status,
            $message,
            ErrorResponse::defaultCodeForStatus($status),
        );
        echo json_encode($payload, JSON_UNESCAPED_UNICODE);
        exit;
    }
}
