<?php
/**
 * Security Middleware
 */
class Middleware {
    
    public static function handle($request) {
        self::checkHttps();
        self::checkMaintenance();
        self::checkIpWhitelist();
        self::checkRateLimit();
    }
    
    private static function checkHttps() {
        if (Config::get('app_env') === 'production' && empty($_SERVER['HTTPS'])) {
            header('Location: https://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
            exit;
        }
    }
    
    private static function checkMaintenance() {
        $maintenance = Database::fetchOne(
            "SELECT setting_value FROM system_settings WHERE setting_key = 'maintenance_mode'"
        );
        
        if ($maintenance && $maintenance['setting_value'] === '1') {
            if (!Auth::check() || !Auth::hasRole('Super Admin Officer')) {
                http_response_code(503);
                include Config::get('app_path') . '/views/errors/maintenance.php';
                exit;
            }
        }
    }
    
    private static function checkIpWhitelist() {
        $whitelistEnabled = Database::fetchOne(
            "SELECT setting_value FROM system_settings WHERE setting_key = 'ip_whitelist_enabled'"
        );
        
        if ($whitelistEnabled && $whitelistEnabled['setting_value'] === '1') {
            $whitelisted = Database::fetchAll(
                "SELECT ip_address FROM ip_whitelist WHERE is_active = 1"
            );
            
            $clientIp = Security::getClientIp();
            $allowed = false;
            
            foreach ($whitelisted as $entry) {
                if (self::ipInRange($clientIp, $entry['ip_address'])) {
                    $allowed = true;
                    break;
                }
            }
            
            if (!$allowed) {
                http_response_code(403);
                die('Access denied. Your IP is not whitelisted.');
            }
        }
    }
    
    private static function checkRateLimit() {
        if (!Auth::check()) {
            $ip = Security::getClientIp();
            $limit = Config::get('rate_limit', 60);
            $window = 60; // 1 minute
            
            $requests = Database::fetchOne(
                "SELECT COUNT(*) as count FROM request_log 
                 WHERE ip_address = ? AND created_at > DATE_SUB(NOW(), INTERVAL ? SECOND)",
                [$ip, $window]
            );
            
            if ($requests['count'] > $limit) {
                http_response_code(429);
                die('Too many requests. Please try again later.');
            }
            
            Database::insert('request_log', [
                'ip_address' => $ip,
                'url' => $_SERVER['REQUEST_URI'],
                'method' => $_SERVER['REQUEST_METHOD']
            ]);
        }
    }
    
    private static function ipInRange($ip, $range) {
        if (strpos($range, '/') === false) {
            return $ip === $range;
        }
        
        list($subnet, $mask) = explode('/', $range);
        $ipLong = ip2long($ip);
        $subnetLong = ip2long($subnet);
        $maskLong = ~((1 << (32 - $mask)) - 1);
        
        return ($ipLong & $maskLong) === ($subnetLong & $maskLong);
    }
}