<?php

/**
 * Security Middleware
 * Handles security checks for requests
 */
class SecurityMiddleware {
    
    /**
     * Verify CSRF token for POST requests
     * 
     * @return bool
     */
    public static function verifyCsrf() {
        if ($_SERVER['REQUEST_METHOD'] === 'POST') {
            $token = $_POST['csrf_token'] ?? '';
            
            if (!verifyCsrfToken($token)) {
                $_SESSION['error'] = 'Invalid security token. Please try again.';
                return false;
            }
        }
        
        return true;
    }
    
    /**
     * Check if user is authenticated
     * 
     * @param string $redirectUrl URL to redirect if not authenticated
     * @return bool
     */
    public static function requireAuth($redirectUrl = null) {
        if (!isAuthenticated()) {
            if ($redirectUrl === null) {
                $redirectUrl = URL_PATH . '/admin/login';
            }
            redirect($redirectUrl);
            return false;
        }
        
        return true;
    }
    
    /**
     * Prevent clickjacking attacks
     */
    public static function setSecurityHeaders() {
        // Prevent clickjacking
        header('X-Frame-Options: SAMEORIGIN');
        
        // XSS protection
        header('X-XSS-Protection: 1; mode=block');
        
        // Prevent MIME sniffing
        header('X-Content-Type-Options: nosniff');
        
        // Referrer policy
        header('Referrer-Policy: strict-origin-when-cross-origin');
        
        // Content Security Policy (basic)
        header("Content-Security-Policy: default-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.jsdelivr.net https://cdnjs.cloudflare.com; img-src 'self' data:;");
    }
    
    /**
     * Validate file upload
     * 
     * @param array $file Uploaded file from $_FILES
     * @param array $allowedTypes Allowed MIME types
     * @param int $maxSize Maximum file size in bytes
     * @return array Result with success status and error message
     */
    public static function validateFileUpload($file, $allowedTypes, $maxSize) {
        $result = [
            'success' => false,
            'error' => null
        ];
        
        // Check if file was uploaded
        if (!isset($file['error']) || is_array($file['error'])) {
            $result['error'] = 'Invalid file upload';
            return $result;
        }
        
        // Check for upload errors
        switch ($file['error']) {
            case UPLOAD_ERR_OK:
                break;
            case UPLOAD_ERR_INI_SIZE:
            case UPLOAD_ERR_FORM_SIZE:
                $result['error'] = 'File size exceeds limit';
                return $result;
            case UPLOAD_ERR_NO_FILE:
                $result['error'] = 'No file uploaded';
                return $result;
            default:
                $result['error'] = 'Unknown upload error';
                return $result;
        }
        
        // Check file size
        if ($file['size'] > $maxSize) {
            $result['error'] = 'File size exceeds maximum allowed size';
            return $result;
        }
        
        // Check MIME type
        $finfo = new finfo(FILEINFO_MIME_TYPE);
        $mimeType = $finfo->file($file['tmp_name']);
        
        if (!in_array($mimeType, $allowedTypes)) {
            $result['error'] = 'Invalid file type';
            return $result;
        }
        
        // Additional security: Check file extension
        $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        $allowedExtensions = [];
        
        foreach ($allowedTypes as $type) {
            switch ($type) {
                case 'image/jpeg':
                    $allowedExtensions[] = 'jpg';
                    $allowedExtensions[] = 'jpeg';
                    break;
                case 'image/png':
                    $allowedExtensions[] = 'png';
                    break;
                case 'image/gif':
                    $allowedExtensions[] = 'gif';
                    break;
                case 'image/webp':
                    $allowedExtensions[] = 'webp';
                    break;
                case 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet':
                    $allowedExtensions[] = 'xlsx';
                    break;
                case 'application/vnd.ms-excel':
                    $allowedExtensions[] = 'xls';
                    break;
                case 'text/csv':
                    $allowedExtensions[] = 'csv';
                    break;
            }
        }
        
        if (!in_array($extension, $allowedExtensions)) {
            $result['error'] = 'Invalid file extension';
            return $result;
        }
        
        $result['success'] = true;
        return $result;
    }
    
    /**
     * Rate limiting check (simple implementation)
     * 
     * @param string $action Action identifier
     * @param int $maxAttempts Maximum attempts allowed
     * @param int $timeWindow Time window in seconds
     * @return bool
     */
    public static function checkRateLimit($action, $maxAttempts = 5, $timeWindow = 300) {
        $key = 'rate_limit_' . $action . '_' . ($_SERVER['REMOTE_ADDR'] ?? 'unknown');
        
        if (!isset($_SESSION[$key])) {
            $_SESSION[$key] = [
                'attempts' => 0,
                'first_attempt' => time()
            ];
        }
        
        $data = $_SESSION[$key];
        
        // Reset if time window has passed
        if (time() - $data['first_attempt'] > $timeWindow) {
            $_SESSION[$key] = [
                'attempts' => 1,
                'first_attempt' => time()
            ];
            return true;
        }
        
        // Check if limit exceeded
        if ($data['attempts'] >= $maxAttempts) {
            return false;
        }
        
        // Increment attempts
        $_SESSION[$key]['attempts']++;
        
        return true;
    }
    
    /**
     * Sanitize array of data
     * 
     * @param array $data
     * @return array
     */
    public static function sanitizeArray($data) {
        $sanitized = [];
        
        foreach ($data as $key => $value) {
            if (is_array($value)) {
                $sanitized[$key] = self::sanitizeArray($value);
            } else {
                $sanitized[$key] = sanitize($value);
            }
        }
        
        return $sanitized;
    }
}
