<?php
/**
 * SecurityMiddleware - Middleware de sécurité pour l'API
 * Protection contre CSRF, rate limiting, et autres attaques
 */
class SecurityMiddleware {
    
    private static $rateLimitStore = [];
    
    /**
     * Middleware principal de sécurité
     */
    public static function apply() {
        self::validateHttpMethod();
        self::checkRateLimit();
        self::validateContentType();
        self::sanitizeHeaders();
        
        // Protection supplémentaires en production
        if (!DatabaseConfig::isDevelopment()) {
            self::checkUserAgent();
            self::validateReferer();
        }
    }
    
    /**
     * Valider les méthodes HTTP autorisées
     */
    private static function validateHttpMethod() {
        $allowedMethods = ['GET', 'POST', 'OPTIONS'];
        $method = $_SERVER['REQUEST_METHOD'];
        
        if (!in_array($method, $allowedMethods)) {
            http_response_code(405);
            header('Allow: ' . implode(', ', $allowedMethods));
            Utils::errorResponse('Méthode HTTP non autorisée', 405);
        }
    }
    
    /**
     * Limitation du taux de requêtes (Rate limiting simple)
     */
    private static function checkRateLimit() {
        $clientIp = self::getClientIP();
        $window = 60; // 1 minute
        $maxRequests = 100; // 100 requêtes par minute
        
        $currentTime = time();
        $windowStart = $currentTime - $window;
        
        // Nettoyer les anciennes entrées
        if (!empty(self::$rateLimitStore[$clientIp])) {
            self::$rateLimitStore[$clientIp] = array_filter(
                self::$rateLimitStore[$clientIp],
                function($timestamp) use ($windowStart) {
                    return $timestamp > $windowStart;
                }
            );
        }
        
        // Compter les requêtes actuelles
        $requestCount = count(self::$rateLimitStore[$clientIp] ?? []);
        
        if ($requestCount >= $maxRequests) {
            http_response_code(429);
            header('Retry-After: 60');
            Utils::logError("Rate limit dépassé pour IP: $clientIp");
            Utils::errorResponse('Trop de requêtes. Réessayez dans 1 minute.', 429);
        }
        
        // Enregistrer cette requête
        self::$rateLimitStore[$clientIp][] = $currentTime;
    }
    
    /**
     * Valider le Content-Type pour les requêtes POST
     */
    private static function validateContentType() {
        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            $contentType = $_SERVER['CONTENT_TYPE'] ?? '';
            $allowedTypes = [
                'application/json',
                'application/x-www-form-urlencoded',
                'multipart/form-data'
            ];
            
            $isValidType = false;
            foreach ($allowedTypes as $type) {
                if (strpos($contentType, $type) === 0) {
                    $isValidType = true;
                    break;
                }
            }
            
            if (!$isValidType) {
                Utils::errorResponse('Content-Type non supporté', 415);
            }
        }
    }
    
    /**
     * Nettoyer et valider les headers
     */
    private static function sanitizeHeaders() {
        // Headers potentiellement dangereux
        $dangerousHeaders = [
            'X-Forwarded-Host',
            'X-Original-URL',
            'X-Rewrite-URL'
        ];
        
        foreach ($dangerousHeaders as $header) {
            $serverKey = 'HTTP_' . str_replace('-', '_', strtoupper($header));
            if (isset($_SERVER[$serverKey])) {
                unset($_SERVER[$serverKey]);
            }
        }
        
        // Valider le header Authorization si présent
        if (isset($_SERVER['HTTP_AUTHORIZATION'])) {
            $auth = $_SERVER['HTTP_AUTHORIZATION'];
            // Vérifier le format Bearer token
            if (!preg_match('/^Bearer\s+[A-Za-z0-9\-_=.]+$/', $auth)) {
                Utils::errorResponse('Format d\'autorisation invalide', 401);
            }
        }
    }
    
    /**
     * Vérifier le User-Agent (protection basique contre les bots)
     */
    private static function checkUserAgent() {
        $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? '';
        
        if (empty($userAgent)) {
            Utils::errorResponse('User-Agent requis', 400);
        }
        
        // Blacklist de User-Agents suspects
        $suspiciousAgents = [
            'curl', 'wget', 'python-requests', 'bot', 'crawler', 'spider'
        ];
        
        $lowerUA = strtolower($userAgent);
        foreach ($suspiciousAgents as $suspect) {
            if (strpos($lowerUA, $suspect) !== false) {
                Utils::logError("User-Agent suspect détecté: $userAgent");
                Utils::errorResponse('Accès non autorisé', 403);
            }
        }
    }
    
    /**
     * Valider le Referer (protection CSRF basique)
     */
    private static function validateReferer() {
        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            $referer = $_SERVER['HTTP_REFERER'] ?? '';
            $host = $_SERVER['HTTP_HOST'] ?? '';
            
            // Permettre les requêtes sans referer (applications mobiles)
            if (empty($referer)) {
                return;
            }
            
            $refererHost = parse_url($referer, PHP_URL_HOST);
            if ($refererHost !== $host) {
                Utils::logError("Referer suspect détecté: $referer");
                Utils::errorResponse('Requête cross-origin non autorisée', 403);
            }
        }
    }
    
    /**
     * Obtenir l'IP réelle du client
     */
    private static function getClientIP() {
        // Headers à vérifier par ordre de priorité
        $headers = [
            'HTTP_X_REAL_IP',
            'HTTP_X_FORWARDED_FOR',
            'HTTP_CLIENT_IP',
            'REMOTE_ADDR'
        ];
        
        foreach ($headers as $header) {
            if (!empty($_SERVER[$header])) {
                $ip = $_SERVER[$header];
                
                // Si X-Forwarded-For, prendre la première IP
                if ($header === 'HTTP_X_FORWARDED_FOR') {
                    $ips = explode(',', $ip);
                    $ip = trim($ips[0]);
                }
                
                // Valider l'IP
                if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
                    return $ip;
                }
            }
        }
        
        return $_SERVER['REMOTE_ADDR'] ?? 'unknown';
    }
    
    /**
     * Générer un token CSRF
     */
    public static function generateCSRFToken() {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }
        
        if (empty($_SESSION['csrf_token'])) {
            $_SESSION['csrf_token'] = bin2hex(random_bytes(32));
        }
        
        return $_SESSION['csrf_token'];
    }
    
    /**
     * Valider un token CSRF
     */
    public static function validateCSRFToken($token) {
        if (session_status() === PHP_SESSION_NONE) {
            session_start();
        }
        
        $sessionToken = $_SESSION['csrf_token'] ?? '';
        
        if (empty($sessionToken) || !hash_equals($sessionToken, $token)) {
            Utils::errorResponse('Token CSRF invalide', 403);
        }
    }
    
    /**
     * Middleware d'authentification JWT
     */
    public static function requireAuth() {
        try {
            require_once 'JwtManager.php';
            $payload = JwtManager::requireAuth();
            return $payload;
        } catch (Exception $e) {
            Utils::logError("Échec d'authentification: " . $e->getMessage());
            Utils::errorResponse('Authentification requise', 401);
        }
    }
    
    /**
     * Logging de sécurité
     */
    public static function logSecurityEvent($event, $details = []) {
        $clientIp = self::getClientIP();
        $userAgent = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';
        $timestamp = date('Y-m-d H:i:s');
        
        $logData = [
            'timestamp' => $timestamp,
            'event' => $event,
            'ip' => $clientIp,
            'user_agent' => $userAgent,
            'details' => $details
        ];
        
        Utils::logError("SECURITY: $event", $logData);
    }
    
    /**
     * Protection contre les attaques de timing
     */
    public static function constantTimeDelay($minTime = 100000) {
        // Délai minimum en microsecondes (100ms par défaut)
        $elapsed = microtime(true) - ($_SERVER['REQUEST_TIME_FLOAT'] ?? microtime(true));
        $elapsedMicro = $elapsed * 1000000;
        
        if ($elapsedMicro < $minTime) {
            usleep($minTime - $elapsedMicro);
        }
    }
    
    /**
     * Headers de sécurité supplémentaires
     */
    public static function setSecurityHeaders() {
        header('X-Content-Type-Options: nosniff');
        header('X-Frame-Options: DENY');
        header('X-XSS-Protection: 1; mode=block');
        header('Referrer-Policy: strict-origin-when-cross-origin');
        
        if (!DatabaseConfig::isDevelopment()) {
            header('Strict-Transport-Security: max-age=31536000; includeSubDomains');
        }
    }
}
?>