<?php
/**
 * Country Blocker - Real-time Enforcement
 * 
 * Handles country-based blocking with GeoIP lookup and caching
 *
 * @package VMPFence
 * @since 2.2.0
 */

if (!defined('ABSPATH')) {
    exit;
}

/**
 * Country Blocking Enforcement Class
 */
class VMPFence_Country_Blocker {

    /**
     * Initialize country blocker
     */
    public static function init() {
        // Hook into WordPress init (fires after plugins_loaded)
        add_action('init', [__CLASS__, 'check_visitor'], 1);
    }

    /**
     * Check if current visitor should be blocked by country
     */
    public static function check_visitor() {
        // Skip checks for admin, AJAX, REST API, CLI, or if disabled
        if (is_admin() || wp_doing_ajax() || wp_doing_cron() || (defined('REST_REQUEST') && REST_REQUEST) || (defined('WP_CLI') && WP_CLI)) {
            return;
        }

        try {
            // Check if feature is enabled
            if (!self::is_feature_enabled()) {
                return;
            }

            // Get visitor IP
            $ip = self::get_visitor_ip();
            if (!$ip || $ip === '127.0.0.1' || $ip === '::1') {
                return; // Skip localhost
            }

            // Check bypass mechanisms first
            if (self::check_bypass()) {
                return;
            }

            // Get country code (with caching)
            $country_code = self::get_country_code($ip);
            if (!$country_code) {
                // if (defined('WP_DEBUG') && WP_DEBUG) {
                //     error_log('VMPFence Country Blocker: Could not determine country for IP: ' . $ip);
                // }
                return; // Couldn't determine country
            }
            
            // Log successful country detection
            // if (defined('WP_DEBUG') && WP_DEBUG) {
            //     error_log('VMPFence Country Blocker: IP ' . $ip . ' detected as country: ' . $country_code);
            // }
            
            // Validate country code format (must be 2 uppercase letters)
            if (!preg_match('/^[A-Z]{2}$/', $country_code)) {
                if (class_exists('VMPFence_Secure_Logger')) {
                    VMPFence_Secure_Logger::log('warning', 'Invalid country code format from GeoIP', [
                        'ip' => $ip,
                        'country_code' => $country_code
                    ]);
                }
                return;
            }

            // Check if country is blocked
            if (!class_exists('VMPFence_Blocked_Country')) {
                return;
            }

            $blocked = VMPFence_Blocked_Country::is_country_blocked($country_code);
            if (!$blocked) {
                // if (defined('WP_DEBUG') && WP_DEBUG) {
                //     error_log('VMPFence Country Blocker: Country ' . $country_code . ' is not in blocked list');
                // }
                return; // Not blocked
            }
            
            // Log that country is blocked
            // if (defined('WP_DEBUG') && WP_DEBUG) {
            //     error_log('VMPFence Country Blocker: Country ' . $country_code . ' IS BLOCKED - evaluating block type...');
            // }

            // Determine blocking type
            $block_site = isset($blocked['block_site']) && $blocked['block_site'] == 1;
            $block_login = isset($blocked['block_login']) && $blocked['block_login'] == 1;

            // Check if we should block this request
            $should_block = false;
            
            if ($block_site) {
                // Block entire site access
                $should_block = true;
            } elseif ($block_login && self::is_login_request()) {
                // Block only login attempts (when site access is allowed)
                $should_block = true;
            }
            
            // Edge case: If neither block_site nor block_login is set, don't block
            // This handles corrupted database entries
            if (!$block_site && !$block_login) {
                return;
            }

            if (!$should_block) {
                return;
            }

            // Increment block counter
            VMPFence_Blocked_Country::increment_block_count($country_code);

            // Log the block
            self::log_block($ip, $country_code, $blocked);

            // Enforce block
            self::enforce_block($country_code, $blocked);
            
        } catch (Exception $e) {
            // Log error but don't break site
            if (class_exists('VMPFence_Secure_Logger')) {
                VMPFence_Secure_Logger::log('error', 'Country blocker error: ' . $e->getMessage(), [
                    'trace' => $e->getTraceAsString()
                ]);
            }
            // Fail open - don't block on error
            return;
        }
    }

    /**
     * Check if feature is enabled
     */
    private static function is_feature_enabled() {
        // Premium license check (country blocking is premium only)
        if (!class_exists('VMPFence_License')) {
            // if (defined('WP_DEBUG') && WP_DEBUG) {
            //     error_log('VMPFence Country Blocker: VMPFence_License class not found');
            // }
            return false;
        }
        
        $license_type = VMPFence_License::get_license_type();
        
        // Log license type for debugging
        // if (defined('WP_DEBUG') && WP_DEBUG) {
        //     error_log('VMPFence Country Blocker: License type = ' . var_export($license_type, true));
        // }
        
        // Check for premium license (with fallback for missing constants)
        $is_premium = false;
        if (class_exists('VMPFence_Constants')) {
            $is_premium = ($license_type === VMPFence_Constants::LICENSE_PREMIUM);
        } else {
            // Fallback: string comparison
            $is_premium = ($license_type === 'premium' || $license_type === 'Premium');
        }
        
        if (!$is_premium) {
            // if (defined('WP_DEBUG') && WP_DEBUG) {
            //     error_log('VMPFence Country Blocker: Not premium license, feature disabled');
            // }
            return false;
        }
        
        // Check if any countries are actually blocked
        // If no countries blocked, no need to run checks
        if (!class_exists('VMPFence_Blocked_Country')) {
            return false;
        }
        
        // Simple check: at least one active country exists
        // Use a cached transient to avoid DB query on every request
        $has_blocked_countries = get_transient('vmpfence_has_blocked_countries');
        
        if ($has_blocked_countries === false) {
            // Cache miss - query database
            global $wpdb;
            $table = $wpdb->prefix . 'vmpfence_blocked_countries';
            
            // Check if table exists first
            $table_exists = $wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $table));
            
            if ($table_exists !== $table) {
                return false;
            }
            
            // Query blocked countries count (no prepare needed for static query with esc_sql)
            $count = $wpdb->get_var("SELECT COUNT(*) FROM " . esc_sql($table) . " WHERE is_active = 1");
            $has_blocked_countries = ($count > 0) ? 'yes' : 'no';
            
            // Log for debugging
            // if (defined('WP_DEBUG') && WP_DEBUG) {
            //     error_log('VMPFence Country Blocker: Found ' . $count . ' blocked countries in database');
            // }
            
            // Cache for 5 minutes
            set_transient('vmpfence_has_blocked_countries', $has_blocked_countries, 5 * MINUTE_IN_SECONDS);
        }
        
        // if (defined('WP_DEBUG') && WP_DEBUG && $has_blocked_countries === 'no') {
        //     error_log('VMPFence Country Blocker: No blocked countries found - feature disabled');
        // }
        
        return ($has_blocked_countries === 'yes');
    }

    /**
     * Get visitor IP address
     */
    private static function get_visitor_ip() {
        $ip = '';

        // Check various headers for proxy/CDN scenarios
        $headers = [
            'HTTP_CF_CONNECTING_IP', // Cloudflare
            'HTTP_X_FORWARDED_FOR',
            'HTTP_X_REAL_IP',
            'REMOTE_ADDR'
        ];

        foreach ($headers as $header) {
            if (!empty($_SERVER[$header])) {
                $ip = $_SERVER[$header];
                
                // Handle comma-separated IPs (X-Forwarded-For)
                if (strpos($ip, ',') !== false) {
                    $ips = explode(',', $ip);
                    $ip = trim($ips[0]);
                }
                
                // Validate IP (both IPv4 and IPv6, exclude private/reserved ranges for public blocking)
                if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
                    break;
                }
            }
        }

        // If no valid public IP found, return empty (will be caught by localhost check)
        return $ip;
    }

    /**
     * Check bypass mechanisms
     */
    private static function check_bypass() {
        // 1. Check if user is logged in admin (not just any user)
        if (is_user_logged_in() && current_user_can('manage_options')) {
            return true;
        }
        
        // 2. Check if logged-in users should bypass (new feature)
        // Default is 0 (allow logged-in users to bypass)
        if (is_user_logged_in() && class_exists('VMPFence_Config')) {
            $block_logged_in = VMPFence_Config::get('country_block_logged_in', 0);
            if ($block_logged_in == 0) {
                // Setting is disabled, allow logged-in users to bypass
                return true;
            }
        }

        // 3. Check bypass cookie
        $bypass_cookie = get_option('vmpfence_country_bypass_cookie', '');
        if (!empty($bypass_cookie) && isset($_COOKIE['vmpfence_bypass']) && $_COOKIE['vmpfence_bypass'] === $bypass_cookie) {
            return true;
        }

        // 4. Check bypass URL parameter
        $bypass_field = get_option('vmpfence_country_bypass_field', '');
        $bypass_value = get_option('vmpfence_country_bypass_value', '');
        
        // Debug logging
        // if (defined('WP_DEBUG') && WP_DEBUG) {
        //     error_log('VMPFence Bypass Check: field=' . $bypass_field . ', value=' . $bypass_value . ', GET=' . print_r($_GET, true));
        // }
        
        if (!empty($bypass_field) && !empty($bypass_value)) {
            // Validate GET parameter exists and is not empty
            if (isset($_GET[$bypass_field]) && !empty($_GET[$bypass_field])) {
                // if (defined('WP_DEBUG') && WP_DEBUG) {
                //     error_log('VMPFence Bypass: GET parameter found, comparing values...');
                // }
                // Use timing-safe comparison to prevent timing attacks
                if (hash_equals($bypass_value, $_GET[$bypass_field])) {
                    // if (defined('WP_DEBUG') && WP_DEBUG) {
                    //     error_log('VMPFence Bypass: MATCH! Allowing access and setting cookie');
                    // }
                    // Set bypass cookie for 30 days with secure flags
                    $cookie_value = $bypass_cookie ?: $bypass_value;
                    $secure = is_ssl();
                    
                    // PHP 7.3+ supports array options for setcookie
                    // Plugin requires PHP 7.4+, so this is safe
                    if (PHP_VERSION_ID >= 70300) {
                        setcookie(
                            'vmpfence_bypass',
                            $cookie_value,
                            array(
                                'expires' => time() + (30 * 24 * 3600),
                                'path' => '/',
                                'domain' => '',
                                'secure' => $secure,
                                'httponly' => true,
                                'samesite' => 'Strict'
                            )
                        );
                    } else {
                        // Fallback for PHP < 7.3 (shouldn't happen, but defensive programming)
                        setcookie('vmpfence_bypass', $cookie_value, time() + (30 * 24 * 3600), '/', '', $secure, true);
                    }
                    return true;
                }
            }
        }

        // 4. Check IP allowlist
        if (class_exists('VMPFence_Config')) {
            $allowlisted_ips = VMPFence_Config::get('ip_allowlist', []);
            $visitor_ip = self::get_visitor_ip();
            
            if (in_array($visitor_ip, $allowlisted_ips)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Get country code from IP with caching
     */
    private static function get_country_code($ip) {
        // Use local GeoIP database lookup (standalone, no API dependency)
        if (!class_exists('VMPFence_GeoIP_Lookup')) {
            return false;
        }

        try {
            // Local database lookup (<5ms with caching)
            $country_code = VMPFence_GeoIP_Lookup::lookup($ip);

            if ($country_code) {
                return $country_code;
            }
        } catch (Exception $e) {
            if (class_exists('VMPFence_Secure_Logger')) {
                VMPFence_Secure_Logger::log('error', 'GeoIP lookup failed', [
                    'ip' => $ip,
                    'error' => $e->getMessage()
                ]);
            }
        }

        return false;
    }

    /**
     * Check if current request is a login attempt
     */
    private static function is_login_request() {
        // Don't block admin-ajax.php even if login action present
        if (isset($_SERVER['SCRIPT_NAME']) && strpos($_SERVER['SCRIPT_NAME'], 'admin-ajax.php') !== false) {
            return false;
        }
        
        // Check if accessing wp-login.php
        if (isset($_SERVER['SCRIPT_NAME']) && strpos($_SERVER['SCRIPT_NAME'], 'wp-login.php') !== false) {
            return true;
        }

        // Check if POST to wp-login.php
        if (isset($_SERVER['REQUEST_URI']) && strpos($_SERVER['REQUEST_URI'], 'wp-login.php') !== false) {
            return true;
        }

        // Check for login action
        if (isset($_REQUEST['action']) && in_array($_REQUEST['action'], ['login', 'lostpassword', 'register'])) {
            return true;
        }

        return false;
    }

    /**
     * Log the country block
     */
    private static function log_block($ip, $country_code, $blocked_data) {
        // Determine block type
        $block_type = (isset($blocked_data['block_site']) && $blocked_data['block_site'] == 1) ? 'site' : 'login';
        
        // Log to dedicated country block logs table
        if (class_exists('VMPFence_Blocked_Country')) {
            VMPFence_Blocked_Country::log_block_event([
                'ip' => $ip,
                'country_code' => $country_code,
                'country_name' => isset($blocked_data['country_name']) ? $blocked_data['country_name'] : '',
                'block_type' => $block_type,
                'request_uri' => isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '',
                'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ''
            ]);
        }

        // Log to secure logger (if available)
        if (class_exists('VMPFence_Secure_Logger')) {
            VMPFence_Secure_Logger::log('info', 'Country block enforced', [
                'ip' => $ip,
                'country_code' => $country_code,
                'country_name' => $blocked_data['country_name'] ?? 'Unknown',
                'block_type' => $block_type,
                'uri' => isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : ''
            ]);
        }

        // Log to API via Logging Service (if available)
        if (class_exists('VMPFence_Logging_Service')) {
            try {
                $logging_service = VMPFence_Logging_Service::get_instance();
                $logging_service->log_event('country_blocked', 'warning', [
                    'country_code' => $country_code,
                    'country_name' => $blocked_data['country_name'] ?? 'Unknown',
                    'ip' => $ip,
                    'block_type' => $block_type,
                    'uri' => isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '',
                    'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : ''
                ], 'firewall');
            } catch (Exception $e) {
                // Silently fail - don't break the block
                // if (defined('WP_DEBUG') && WP_DEBUG) {
                //     error_log('VMPFence Country Blocker: Failed to log event - ' . $e->getMessage());
                // }
            }
        }
    }

    /**
     * Enforce country block (show 403 page)
     */
    private static function enforce_block($country_code, $blocked_data) {
        // Check action type from settings (message or redirect)
        $block_action = 'message';
        if (class_exists('VMPFence_Config')) {
            $block_action = VMPFence_Config::get('country_block_action', 'message');
        }
        
        // If redirect action is selected, check for redirect URL
        if ($block_action === 'redirect') {
            $redirect_url = get_option('vmpfence_country_block_redirect', '');
            
            if (!empty($redirect_url)) {
                wp_redirect($redirect_url);
                exit;
            }
            // If redirect URL is empty, fall back to message
        }
        
        // Show 403 message page (default or fallback)
        status_header(403);
        nocache_headers();

        $country_name = $blocked_data['country_name'] ?? $country_code;
        $reason = $blocked_data['reason'] ?? 'Security policy';

        // Get site name
        $site_name = get_bloginfo('name');

        // Output 403 page
        ?>
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Access Denied - <?php echo esc_html($site_name); ?></title>
    <style>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            display: flex;
            align-items: center;
            justify-content: center;
            min-height: 100vh;
            padding: 20px;
        }
        .container {
            background: white;
            border-radius: 16px;
            box-shadow: 0 20px 60px rgba(0,0,0,0.3);
            max-width: 600px;
            width: 100%;
            padding: 48px 40px;
            text-align: center;
        }
        .icon {
            width: 80px;
            height: 80px;
            margin: 0 auto 24px;
            background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
            border-radius: 50%;
            display: flex;
            align-items: center;
            justify-content: center;
            font-size: 40px;
        }
        h1 {
            font-size: 32px;
            color: #1a1a1a;
            margin-bottom: 16px;
            font-weight: 700;
        }
        .country {
            font-size: 18px;
            color: #666;
            margin-bottom: 24px;
            padding: 12px 24px;
            background: #f5f5f5;
            border-radius: 8px;
            display: inline-block;
        }
        .message {
            font-size: 16px;
            color: #666;
            line-height: 1.6;
            margin-bottom: 24px;
        }
        .reason {
            font-size: 14px;
            color: #999;
            padding: 16px;
            background: #f9f9f9;
            border-left: 4px solid #f5576c;
            border-radius: 4px;
            text-align: left;
            margin-bottom: 32px;
        }
        .footer {
            font-size: 13px;
            color: #999;
            border-top: 1px solid #e5e5e5;
            padding-top: 24px;
        }
        .powered {
            color: #764ba2;
            font-weight: 600;
        }
    </style>
</head>
<body>
    <div class="container">
        <div class="icon">🚫</div>
        <h1>Access Denied</h1>
        <div class="country">
            Access from <strong><?php echo esc_html($country_name); ?></strong> is not permitted
        </div>
        <p class="message">
            We're sorry, but access to this website is currently restricted from your location 
            due to our security policy.
        </p>
        <div class="reason">
            <strong>Reason:</strong> <?php echo esc_html($reason); ?>
        </div>
        <div class="footer">
            If you believe this is an error, please contact the site administrator.
            <br><br>
            <span class="powered">Protected by VMPFence Security</span>
        </div>
    </div>
</body>
</html>
        <?php
        exit;
    }
}
