<?php

class Security
{
    public static function setSecurityHeaders(): void
    {
        // Remove server information
        header('Server: ');
        header('X-Powered-By: ');

        // Content Security Policy
        $csp = self::buildCSP();
        header("Content-Security-Policy: {$csp}");

        // XSS Protection
        header('X-XSS-Protection: 1; mode=block');

        // Frame protection
        header('X-Frame-Options: SAMEORIGIN');

        // MIME type sniffing protection
        header('X-Content-Type-Options: nosniff');

        // Referrer Policy
        header('Referrer-Policy: strict-origin-when-cross-origin');

        // Permissions Policy (Feature Policy)
        $permissionsPolicy = self::buildPermissionsPolicy();
        header("Permissions-Policy: {$permissionsPolicy}");

        // HSTS (HTTPS only)
        if (self::isHttps()) {
            header('Strict-Transport-Security: max-age=31536000; includeSubDomains; preload');
        }

        // Cache control for sensitive pages
        if (self::isSensitivePage()) {
            header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
            header('Pragma: no-cache');
            header('Expires: 0');
        }
    }

    private static function buildCSP(): string
    {
        // Get domain from APP_URL for dynamic CSP configuration
        $appUrl = Env::get('APP_URL', 'http://localhost');
        $parsedUrl = parse_url($appUrl);
        $domain = $parsedUrl['host'] ?? 'localhost';
        $scheme = $parsedUrl['scheme'] ?? 'http';
        $port = $parsedUrl['port'] ?? ($scheme === 'https' ? 443 : 80);
        
        // Build domain URLs for CSP
        $domainUrl = "{$scheme}://{$domain}";
        $domainUrlWithPort = ($port !== 80 && $port !== 443) ? "{$domainUrl}:{$port}" : $domainUrl;
        
                
        // Development localhost URLs
        $localhostHttp = 'http://localhost:8000';
        $localhostHttps = 'https://localhost:8000';

        $directives = [
            "default-src 'self'",
            "script-src 'self' 'unsafe-inline' https://www.google.com https://www.gstatic.com https://static.cloudflareinsights.com https://www.google.com/recaptcha https://cdn.jsdelivr.net https://cdn.tiny.cloud https://unpkg.com {$localhostHttp} {$localhostHttps} {$domainUrl} {$domainUrlWithPort}",
            "style-src 'self' 'unsafe-inline' https://fonts.googleapis.com https://cdn.jsdelivr.net https://cdn.tiny.cloud https://unpkg.com {$localhostHttp} {$localhostHttps} {$domainUrl} {$domainUrlWithPort}",
            "img-src 'self' data: blob: https: http: {$localhostHttp} {$localhostHttps} {$domainUrl} {$domainUrlWithPort}",
            "font-src 'self' data: https://fonts.gstatic.com {$localhostHttp} {$localhostHttps} {$domainUrl} {$domainUrlWithPort}",
            "connect-src 'self' https://www.google.com https://www.google.com/recaptcha https://static.cloudflareinsights.com https://cdn.tiny.cloud {$localhostHttp} {$localhostHttps} {$domainUrl} {$domainUrlWithPort}",
            "frame-src 'self' https://www.google.com https://www.gstatic.com",
            "object-src 'none'",
            "base-uri 'self'",
            "form-action 'self' {$localhostHttp} {$localhostHttps} {$domainUrl} {$domainUrlWithPort}",
        ];

        // Only add upgrade-insecure-requests for production HTTPS sites
        if ($scheme === 'https' && !in_array($domain, ['localhost', '127.0.0.1'])) {
            $directives[] = "upgrade-insecure-requests";
        }

        return implode('; ', $directives);
    }

    private static function buildPermissionsPolicy(): string
    {
        $features = [
            'geolocation=()',
            'microphone=()',
            'camera=()',
            'payment=()',
            'usb=()',
            'magnetometer=()',
            'gyroscope=()',
            'accelerometer=()',
            'ambient-light-sensor=()',
            'autoplay=(self)',
            'encrypted-media=(self)',
            'fullscreen=(self)',
            'picture-in-picture=(self)'
        ];

        return implode(', ', $features);
    }

    private static function isHttps(): bool
    {
        return (
            (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ||
            $_SERVER['SERVER_PORT'] == 443 ||
            (isset($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')
        );
    }

    private static function isSensitivePage(): bool
    {
        $uri = $_SERVER['REQUEST_URI'] ?? '';
        $sensitivePaths = [
            '/login',
            '/register',
            '/profile',
            '/admin',
            '/forgot-password',
            '/reset-password'
        ];

        foreach ($sensitivePaths as $path) {
            if (str_starts_with($uri, $path)) {
                return true;
            }
        }

        return false;
    }

    public static function sanitizeInput(mixed $input): mixed
    {
        if (is_array($input)) {
            return array_map([self::class, 'sanitizeInput'], $input);
        } elseif (is_string($input)) {
            return htmlspecialchars(trim($input), ENT_QUOTES | ENT_HTML5, 'UTF-8');
        }

        return $input;
    }

    public static function sanitizeFilename(string $filename): string
    {
        // Remove path components
        $filename = basename($filename);
        
        // Remove dangerous characters
        $filename = preg_replace('/[^a-zA-Z0-9._-]/', '', $filename);
        
        // Prevent hidden files
        if (str_starts_with($filename, '.')) {
            $filename = 'file_' . $filename;
        }
        
        return $filename;
    }

    public static function generateSecureToken(int $length = 32): string
    {
        return bin2hex(random_bytes($length));
    }

    public static function isValidCsrfToken(string $token): bool
    {
        $storedToken = Session::get('csrf_token', '');
        return hash_equals($storedToken, $token);
    }

    public static function rateLimitCheck(string $identifier, int $maxAttempts = 5, int $windowSeconds = 300): bool
    {
        $key = "rate_limit_{$identifier}";
        $attempts = Session::get($key, 0);
        $lastAttempt = Session::get("{$key}_time", 0);

        // Reset window if expired
        if (time() - $lastAttempt > $windowSeconds) {
            Session::set($key, 1);
            Session::set("{$key}_time", time());
            return true;
        }

        // Check if limit exceeded
        if ($attempts >= $maxAttempts) {
            return false;
        }

        // Increment attempts
        Session::set($key, $attempts + 1);
        Session::set("{$key}_time", time());
        
        return true;
    }

    public static function logSecurityEvent(string $event, array $context = []): void
    {
        $logEntry = [
            'timestamp' => date('Y-m-d H:i:s'),
            'event' => $event,
            'ip' => $_SERVER['REMOTE_ADDR'] ?? 'unknown',
            'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'unknown',
            'user_id' => Session::getUserId(),
            'context' => $context
        ];

        error_log('SECURITY: ' . json_encode($logEntry));
    }
}
