<?php
declare(strict_types=1);

namespace App\Security;

final class HttpSecurityHeaders
{
    public static function apply(bool $isHttps): void
    {
        $environment = strtolower((string)($_ENV['APP_ENV'] ?? 'production'));
        $production = $environment === 'production';

        header('X-Content-Type-Options: nosniff');
        header('X-Frame-Options: DENY');
        header('Referrer-Policy: strict-origin-when-cross-origin');
        header('Permissions-Policy: camera=(), microphone=(), geolocation=(), payment=(), usb=(), browsing-topics=()');
        header('Cross-Origin-Opener-Policy: same-origin');
        header('Cross-Origin-Resource-Policy: same-origin');
        header('X-Permitted-Cross-Domain-Policies: none');
        header('Cache-Control: no-store, private');

        if ($production && $isHttps) {
            $maxAge = self::intEnv('HSTS_MAX_AGE', 31536000, 300, 63072000);
            $value = 'max-age=' . $maxAge;
            if (self::boolEnv('HSTS_INCLUDE_SUBDOMAINS', true)) $value .= '; includeSubDomains';
            if (self::boolEnv('HSTS_PRELOAD', false)) $value .= '; preload';
            header('Strict-Transport-Security: ' . $value);
        }

        $compatible = "default-src 'self'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; object-src 'none'; "
            . "script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; "
            . "font-src 'self' data:; connect-src 'self'; media-src 'self'; worker-src 'self' blob:; manifest-src 'self'; upgrade-insecure-requests";
        $strictReport = "default-src 'self'; base-uri 'self'; form-action 'self'; frame-ancestors 'none'; object-src 'none'; "
            . "script-src 'self'; style-src 'self' 'unsafe-inline'; img-src 'self' data: blob:; font-src 'self' data:; connect-src 'self'; media-src 'self'; worker-src 'self' blob:; manifest-src 'self'";

        if ($production && self::boolEnv('CSP_ENFORCE', true)) {
            header('Content-Security-Policy: ' . $compatible);
        } else {
            header('Content-Security-Policy: frame-ancestors \'none\'; base-uri \'self\'; form-action \'self\'; object-src \'none\'');
        }
        if (self::boolEnv('CSP_REPORT_ONLY_STRICT', true)) {
            header('Content-Security-Policy-Report-Only: ' . $strictReport);
        }
    }

    public static function applyCors(string $method, string $path): void
    {
        if (!str_starts_with($path, '/api/')) return;
        $origin = trim((string)($_SERVER['HTTP_ORIGIN'] ?? ''));
        $allowed = array_values(array_filter(array_map('trim', explode(',', (string)($_ENV['CORS_ALLOWED_ORIGINS'] ?? '')))));
        if ($origin !== '' && in_array($origin, $allowed, true)) {
            header('Access-Control-Allow-Origin: ' . $origin);
            header('Vary: Origin');
            header('Access-Control-Allow-Credentials: true');
        }
        if ($method === 'OPTIONS') {
            header('Access-Control-Allow-Methods: GET, POST, OPTIONS');
            header('Access-Control-Allow-Headers: Content-Type, Authorization, X-CSRF-Token');
            header('Access-Control-Max-Age: 600');
        }
    }

    private static function boolEnv(string $name, bool $default): bool
    {
        $value = filter_var($_ENV[$name] ?? $default, FILTER_VALIDATE_BOOL, FILTER_NULL_ON_FAILURE);
        return $value ?? $default;
    }

    private static function intEnv(string $name, int $default, int $min, int $max): int
    {
        $value = filter_var($_ENV[$name] ?? $default, FILTER_VALIDATE_INT);
        return max($min, min($max, $value === false ? $default : $value));
    }
}
