<?php
/**
 * Blocked IP Model
 *
 * Manages blocked IP addresses with bidirectional sync to API server
 *
 * @package VMPFence
 * @since 2.1.0
 * @since 2.2.0 -- Added timestamp parameter for API sync
 * @since 2.2.4 -- Added refresh license check after successful sync to ensure license is valid and active
 */

// Prevent direct access
if (!defined('ABSPATH')) {
    exit;
}

/**
 * Blocked IP Management Class
 *
 * @since 1.0.0
 */
class VMPFence_Blocked_IP {

    /**
     * Add IP to blocklist
     *
     * @since 1.0.0
     * @since 2.2.0 timestamp parameter added for API sync
     * @param string $ip IP address to block
     * @param string $reason Reason for blocking
     * @param int $duration_minutes Duration in minutes (0 = permanent)
     * @param string $source Source of block ('local', 'api', 'both')
     * @param string|null $rule_id Associated rule ID if triggered by rule
     * @param int|null $blocked_at_timestamp Optional Unix timestamp for when IP was blocked (defaults to current time)
     * @return int|false Block ID on success, false on failure
     */
    public static function add_blocked_ip($ip, $reason, $duration_minutes = 0, $source = 'local', $rule_id = null, $blocked_at_timestamp = null) {
        global $wpdb;
        
        // Validate IP address or CIDR range
        $is_valid = false;
        $cidr_suffix = '';
        if (strpos($ip, '/') !== false) {
            // CIDR notation (e.g., 192.168.1.0/24)
            list($base_ip, $cidr) = explode('/', $ip, 2);
            $is_valid = filter_var($base_ip, FILTER_VALIDATE_IP) && is_numeric($cidr) && $cidr >= 0 && $cidr <= 128;
            if ($is_valid) {
                $cidr_suffix = '/' . $cidr;
                $ip = $base_ip; // Normalize the base IP first
            }
        } else {
            // Single IP address
            $is_valid = filter_var($ip, FILTER_VALIDATE_IP);
        }
        
        if (!$is_valid) {
            VMPFence_Secure_Logger::warning("Invalid IP format", ['ip' => $ip]);
            return false;
        }
        
        // Normalize IPv6 addresses to compressed format (2001:0db8::1 -> 2001:db8::1)
        // IPv4 addresses remain unchanged
        $ip_binary = @inet_pton($ip);
        if ($ip_binary !== false) {
            $normalized_ip = @inet_ntop($ip_binary);
            if ($normalized_ip !== false) {
                $ip = $normalized_ip;
            }
        }
        
        // Re-add CIDR suffix if it was present
        if ($cidr_suffix !== '') {
            $ip .= $cidr_suffix;
        }
        
        $table = $wpdb->prefix . VMPFence_Constants::TABLE_BLOCKED_IPS;
        
        // Calculate expiration (0 = permanent block, timestamp = temporary block)
        $blocked_until = 0; // Default to permanent (0)
        if ($duration_minutes > 0) {
            // For temporary blocks, use Unix timestamp (int)
            $blocked_until = time() + ($duration_minutes * 60);
        }
        
        // Check if IP already exists
        $existing = $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$table} WHERE ip_address = %s",
            $ip
        ), ARRAY_A);
        
        if ($existing) {
            // Update existing block
            $update_data = array(
                'reason' => $reason,
                'blocked_until' => $blocked_until,
                'is_active' => 1,
                'source' => $source,
                'rule_id' => $rule_id,
                'block_count' => $existing['block_count'] + 1,
                'last_attempt' => current_time('mysql', 1)
            );
            $update_formats = array('%s', '%d', '%d', '%s', '%s', '%d', '%s');
            
            // For API-sourced updates with provided timestamp, update blocked_at too
            // This allows correcting timestamps from API that may have been wrong previously
            if ($blocked_at_timestamp !== null && ($source === 'api' || $source === 'both')) {
                $update_data['blocked_at'] = $blocked_at_timestamp;
                $update_formats[] = '%d'; // Add format for blocked_at (int)
            }
            
            $result = $wpdb->update(
                $table,
                $update_data,
                array('ip_address' => $ip),
                $update_formats,
                array('%s')
            );
            
            if ($result === false) {
                VMPFence_Secure_Logger::error("Failed to update blocked IP", ['ip' => $ip, 'error' => $wpdb->last_error]);
            } else {
                // Log to WAF log for historical tracking (block count increased)
                // Only log pure local blocks to prevent duplicates during API sync operations
                if ($source === 'local' && class_exists('VMPFence_WAF_Log')) {
                    $ip_binary = @inet_pton($ip);
                    if ($ip_binary !== false) {
                        VMPFence_WAF_Log::log_attack(array(
                            'action' => 'block',
                            'actionDescription' => 'IP re-blocked: ' . $reason,
                            'severity' => 2, // medium severity
                            'logMsg' => sprintf('Re-blocked IP %s: %s (attempt #%d, duration: %s)', $ip, $reason, $existing['block_count'] + 1, $duration_minutes > 0 ? $duration_minutes . ' minutes' : 'permanent'),
                            'IP' => $ip_binary,
                            'actionData' => wp_json_encode(array(
                                'duration_minutes' => $duration_minutes,
                                'blocked_until' => $blocked_until,
                                'is_permanent' => ($duration_minutes === 0),
                                'source' => $source,
                                'rule_id' => $rule_id,
                                'block_count' => $existing['block_count'] + 1
                            ))
                        ));
                    }
                }
                
                // Send to API logging service ONLY for locally detected blocks
                // Do NOT log when syncing from API to avoid inflating event counts
                if ($source === 'local' && class_exists('VMPFence_Logging_Service')) {
                    $logging_service = VMPFence_Logging_Service::get_instance();
                    
                    $logging_service->log_event('ip_blocked', 'warning', array(
                        'ip_address' => $ip,
                        'reason' => $reason,
                        'duration_minutes' => $duration_minutes,
                        'blocked_until' => $blocked_until,
                        'is_permanent' => ($duration_minutes === 0),
                        'source' => $source,
                        'rule_id' => $rule_id,
                        'block_count' => $existing['block_count'] + 1
                    ), 'firewall');
                }
            }
            
            return $result !== false ? $existing['id'] : false;
        } else {
            // Insert new block
            // Use provided timestamp or fall back to current time
            $blocked_at = $blocked_at_timestamp ?? time();
            
            $result = $wpdb->insert(
                $table,
                array(
                    'ip_address' => $ip,
                    'reason' => $reason,
                    'blocked_at' => $blocked_at, // Unix timestamp (int) - from API or current time
                    'blocked_until' => $blocked_until,
                    'is_active' => 1,
                    'source' => $source,
                    'rule_id' => $rule_id,
                    'block_count' => 1,
                    'last_attempt' => current_time('mysql', 1)
                ),
                array('%s', '%s', '%d', '%d', '%d', '%s', '%s', '%d', '%s') // %d for blocked_at and blocked_until (int)
            );
            
            if ($result === false) {
                VMPFence_Secure_Logger::error("Failed to insert blocked IP", ['ip' => $ip, 'error' => $wpdb->last_error]);
            } else {
                // Log to WAF log for historical tracking (immutable audit trail)
                // Only log pure local blocks to prevent duplicates during API sync operations
                if ($source === 'local' && class_exists('VMPFence_WAF_Log')) {
                    $ip_binary = @inet_pton($ip);
                    if ($ip_binary !== false) {
                        VMPFence_WAF_Log::log_attack(array(
                            'action' => 'block',
                            'actionDescription' => 'IP blocked: ' . $reason,
                            'severity' => 2, // medium severity
                            'logMsg' => sprintf('Blocked IP %s: %s (duration: %s)', $ip, $reason, $duration_minutes > 0 ? $duration_minutes . ' minutes' : 'permanent'),
                            'IP' => $ip_binary,
                            'actionData' => wp_json_encode(array(
                                'duration_minutes' => $duration_minutes,
                                'blocked_until' => $blocked_until,
                                'is_permanent' => ($duration_minutes === 0),
                                'source' => $source,
                                'rule_id' => $rule_id
                            ))
                        ));
                    }
                }
                
                // Send to API logging service ONLY for locally detected blocks
                // Do NOT log when syncing from API to avoid inflating event counts
                if ($source === 'local' && class_exists('VMPFence_Logging_Service')) {
                    $logging_service = VMPFence_Logging_Service::get_instance();
                    
                    $logging_service->log_event('ip_blocked', 'warning', array(
                        'ip_address' => $ip,
                        'reason' => $reason,
                        'duration_minutes' => $duration_minutes,
                        'blocked_until' => $blocked_until,
                        'is_permanent' => ($duration_minutes === 0),
                        'source' => $source,
                        'rule_id' => $rule_id,
                    ), 'firewall');
                }
            }
            
            return $result ? $wpdb->insert_id : false;
        }
    }

    /**
     * Get blocked IPs
     *
     * @since 1.0.0
     * @param bool $active_only Only return active blocks
     * @param string|null $source Filter by source ('local', 'api', 'both')
     * @param int $limit Number of results to return (0 = all)
     * @param int $offset Offset for pagination
     * @return array List of blocked IPs
     */
    public static function get_blocked_ips($active_only = true, $source = null, $limit = 0, $offset = 0) {
        global $wpdb;
        
        $table = $wpdb->prefix . VMPFence_Constants::TABLE_BLOCKED_IPS;
        
        $where = array();
        $params = array();
        
        // DEBUG: Log incoming parameters
        // error_log('VMPFence get_blocked_ips called - active_only: ' . ($active_only ? 'true' : 'false') . ', source: ' . ($source ? $source : 'null') . ', limit: ' . $limit . ', offset: ' . $offset);
        
        if ($active_only) {
            // Show only active blocks
            $where[] = "is_active = 1";
            $where[] = "(blocked_until = 0 OR blocked_until > %d)"; // 0 = permanent, timestamp = temporary
            $params[] = time(); // Current Unix timestamp
        } else {
            // Show only inactive/expired blocks
            $where[] = "(is_active = 0 OR (blocked_until > 0 AND blocked_until <= %d))";
            $params[] = time(); // Current Unix timestamp
        }
        
        if ($source) {
            $where[] = "source = %s";
            $params[] = $source;
        }
        
        $sql = "SELECT * FROM {$table}";
        if (!empty($where)) {
            $sql .= " WHERE " . implode(' AND ', $where);
        }
        $sql .= " ORDER BY blocked_at DESC";
        
        // Add pagination if limit is specified
        if ($limit > 0) {
            $sql .= " LIMIT %d OFFSET %d";
            $params[] = $limit;
            $params[] = $offset;
        }
        
        if (!empty($params)) {
            $sql = $wpdb->prepare($sql, $params);
        }
        
        // DEBUG: Log final SQL
        // error_log('VMPFence get_blocked_ips SQL: ' . $sql);
        
        $results = $wpdb->get_results($sql, ARRAY_A);
        // error_log('VMPFence get_blocked_ips returned ' . count($results) . ' rows');
        
        return $results;
    }

    /**
     * Get count of blocked IPs
     *
     * @since 1.0.0
     * @param bool $active_only Only count active blocks
     * @param string|null $source Filter by source ('local', 'api', 'both')
     * @return int Count of blocked IPs
     */
    public static function get_blocked_count($active_only = true, $source = null) {
        global $wpdb;
        
        $table = $wpdb->prefix . VMPFence_Constants::TABLE_BLOCKED_IPS;
        
        $where = array();
        $params = array();
        
        if ($active_only) {
            $where[] = "is_active = 1";
            $where[] = "(blocked_until = 0 OR blocked_until > %d)";
            $params[] = time();
        } else {
            $where[] = "(is_active = 0 OR (blocked_until > 0 AND blocked_until <= %d))";
            $params[] = time();
        }
        
        if ($source) {
            $where[] = "source = %s";
            $params[] = $source;
        }
        
        $sql = "SELECT COUNT(*) FROM {$table}";
        if (!empty($where)) {
            $sql .= " WHERE " . implode(' AND ', $where);
        }
        
        if (!empty($params)) {
            $sql = $wpdb->prepare($sql, $params);
        }
        
        return (int) $wpdb->get_var($sql);
    }

    /**
     * Search blocked IPs by IP address or reason
     *
     * @since 2.0.0
     * @param string $search_term Search term for IP or reason
     * @param bool $active_only Only search active blocks
     * @param string|null $source Filter by source ('local', 'api', null for all)
     * @param int $limit Maximum results to return
     * @return array Array with 'results' and 'total_count'
     */
    public static function search_blocked_ips($search_term, $active_only = true, $source = null, $limit = 100) {
        global $wpdb;
        
        $table = $wpdb->prefix . VMPFence_Constants::TABLE_BLOCKED_IPS;
        
        $where = array();
        $params = array();
        
        // Add search condition (IP address or reason)
        $search_term = trim($search_term);
        if (!empty($search_term)) {
            $where[] = "(ip_address LIKE %s OR reason LIKE %s)";
            $params[] = '%' . $wpdb->esc_like($search_term) . '%';
            $params[] = '%' . $wpdb->esc_like($search_term) . '%';
        }
        
        // Add active filter
        if ($active_only) {
            $where[] = "is_active = 1";
            $where[] = "(blocked_until = 0 OR blocked_until > %d)";
            $params[] = time();
        } else {
            $where[] = "(is_active = 0 OR (blocked_until > 0 AND blocked_until <= %d))";
            $params[] = time();
        }
        
        // Add source filter
        if ($source) {
            $where[] = "source = %s";
            $params[] = $source;
        }
        
        $where_clause = !empty($where) ? " WHERE " . implode(' AND ', $where) : "";
        
        // Get total count
        $count_sql = "SELECT COUNT(*) FROM {$table}" . $where_clause;
        if (!empty($params)) {
            $count_sql = $wpdb->prepare($count_sql, $params);
        }
        $total_count = (int) $wpdb->get_var($count_sql);
        
        // Get results with limit (add limit to params array for proper preparation)
        $results_sql = "SELECT * FROM {$table}" . $where_clause . " ORDER BY blocked_at DESC LIMIT %d";
        $results_params = array_merge($params, array($limit)); // Merge limit into params
        
        if (!empty($results_params)) {
            $results_sql = $wpdb->prepare($results_sql, $results_params);
        }
        
        $results = $wpdb->get_results($results_sql, ARRAY_A);
        
        return array(
            'results' => $results,
            'total_count' => $total_count,
            'showing_count' => count($results)
        );
    }

    /**
     * Remove IP from blocklist
     *
     * @since 1.0.0
     * @param string $ip IP address to unblock
     * @return bool Success
     */
    public static function remove_blocked_ip($ip) {
        global $wpdb;
        
        $table = $wpdb->prefix . VMPFence_Constants::TABLE_BLOCKED_IPS;
        
        // Soft delete - mark as inactive
        $result = $wpdb->update(
            $table,
            array('is_active' => 0),
            array('ip_address' => $ip),
            array('%d'),
            array('%s')
        );
        
        return $result !== false;
    }

    /**
     * Permanently delete IP from database
     *
     * @since 2.0.0
     * @param string $ip IP address to delete
     * @return bool Success
     */
    public static function delete_blocked_ip($ip) {
        global $wpdb;
        
        $table = $wpdb->prefix . VMPFence_Constants::TABLE_BLOCKED_IPS;
        
        // Hard delete - permanently remove from database
        $result = $wpdb->delete(
            $table,
            array('ip_address' => $ip),
            array('%s')
        );
        
        return $result !== false;
    }

    /**
     * Check if IP is blocked
     *
     * @since 1.0.0
     * @param string $ip IP address to check
     * @return bool True if blocked
     */
    public static function is_blocked($ip) {
        global $wpdb;
        
        $table = $wpdb->prefix . VMPFence_Constants::TABLE_BLOCKED_IPS;
        
        $count = $wpdb->get_var($wpdb->prepare(
            "SELECT COUNT(*) FROM {$table} 
             WHERE ip_address = %s 
             AND is_active = 1 
             AND (blocked_until = 0 OR blocked_until > %d)", // 0 = permanent, timestamp = temporary
            $ip,
            time() // Current Unix timestamp
        ));
        
        return $count > 0;
    }

    /**
     * Get blocked IP details
     *
     * @since 1.0.0
     * @param string $ip IP address
     * @return array|null IP details or null if not found
     */
    public static function get_blocked_ip_details($ip) {
        global $wpdb;
        
        $table = $wpdb->prefix . VMPFence_Constants::TABLE_BLOCKED_IPS;
        
        return $wpdb->get_row($wpdb->prepare(
            "SELECT * FROM {$table} WHERE ip_address = %s",
            $ip
        ), ARRAY_A);
    }

    /**
     * Sync blocked IPs from API
     *
     * @since 1.0.0
     * @since 2.2.0 -- Timestamp added for API sync
     * @return array Sync statistics (total, new, updated, errors)
     */
    public static function sync_from_api() {
        $stats = array(
            'total' => 0,
            'new' => 0,
            'updated' => 0,
            'errors' => array()
        );
        
        // Note: Syncing from API (pulling IPs) is available for all users
        // Free users can benefit from the global threat intelligence
        // Reporting to API (pushing local IPs) remains premium-only
        
        // Get API key
        $api_key = VMPFence_Config::get('central_api_key');
        if (!$api_key) {
            $stats['errors'][] = 'API key not configured';
            return $stats;
        }
        
        // Fetch blocked IPs from API
        $api_client = new VMPFence_API_Client();
        $response = $api_client->get_blocked_ips($api_key, true); // active_only = true
        
        if (is_wp_error($response)) {
            $stats['errors'][] = 'Failed to fetch blocked IPs from API: ' . $response->get_error_message();
            return $stats;
        }
        
        if (!$response || !isset($response['blocked_ips'])) {
            $stats['errors'][] = 'Invalid API response format';
            return $stats;
        }
        
        $stats['total'] = count($response['blocked_ips']);
        
        // Build list of IPs from API
        $api_ips = array();
        
        // Process each blocked IP from API
        foreach ($response['blocked_ips'] as $blocked_ip) {
            // Convert API schema to plugin schema
            $ip = trim($blocked_ip['ip_address']); // Trim whitespace
            $api_ips[] = $ip; // Track this IP as being on the API
            
            $reason = isset($blocked_ip['reason']) ? $blocked_ip['reason'] : 'Blocked by API';
            $rule_id = isset($blocked_ip['rule_id']) ? $blocked_ip['rule_id'] : null;
            
            // Extract blocked_at timestamp from API (when crawler added it)
            $blocked_at_from_api = null;
            if (isset($blocked_ip['blocked_at']) && $blocked_ip['blocked_at']) {
                // API sends ISO 8601 UTC timestamp: "2025-11-17T11:31:03.339307"
                // Convert to Unix timestamp
                $blocked_at_clean = preg_replace('/\.\d+$/', '', $blocked_ip['blocked_at']); // Remove microseconds
                $timestamp = strtotime($blocked_at_clean . ' UTC');
                // Ensure false values become null (strtotime returns false on failure)
                $blocked_at_from_api = ($timestamp !== false) ? $timestamp : null;
            }
            
            // Calculate duration from expires_at
            $duration_minutes = 0; // Permanent by default
            if (isset($blocked_ip['expires_at']) && $blocked_ip['expires_at']) {
                // API returns ISO 8601 format in UTC: 2025-11-10T10:21:27.100
                // Convert to timestamp - handle both with/without microseconds
                $expires_at_clean = preg_replace('/\.\d+$/', '', $blocked_ip['expires_at']); // Remove microseconds
                
                // Parse as UTC timestamp (API times are in UTC)
                $expires_timestamp = strtotime($expires_at_clean . ' UTC');
                $now = time(); // Current UTC timestamp
                
                if ($expires_timestamp > $now) {
                    $duration_minutes = (int) ceil(($expires_timestamp - $now) / 60);
                } else {
                    // Block already expired, set to 1 minute to mark as temporary but very short
                    $duration_minutes = 1;
                }
            }
            
            VMPFence_Secure_Logger::debug("Syncing IP from API", [
                'ip' => $ip,
                'duration_minutes' => $duration_minutes,
                'expires_at' => $blocked_ip['expires_at'] ?? null
            ]);
            
            // Check if IP already exists locally
            $existing = self::get_blocked_ip_details($ip);
            
            if ($existing) {
                // Update source to 'both' if was 'local'
                $new_source = ($existing['source'] === 'local') ? 'both' : 'api';
                
                $result = self::add_blocked_ip($ip, $reason, $duration_minutes, $new_source, $rule_id, $blocked_at_from_api);
                if ($result) {
                    $stats['updated']++;
                } else {
                    $stats['errors'][] = "Failed to update IP: {$ip} (reason: {$reason}, duration: {$duration_minutes}, source: {$new_source})";
                }
            } else {
                // Add new block from API
                $result = self::add_blocked_ip($ip, $reason, $duration_minutes, 'api', $rule_id, $blocked_at_from_api);
                if ($result) {
                    $stats['new']++;
                } else {
                    global $wpdb;
                    $db_error = $wpdb->last_error ? " DB Error: {$wpdb->last_error}" : "";
                    $stats['errors'][] = "Failed to add IP: {$ip} (reason: {$reason}, duration: {$duration_minutes}, rule_id: {$rule_id}){$db_error}";
                }
            }
        }
        
        // Remove IPs that are no longer on the API (but keep 'local' and 'both' sources)
        // Only deactivate IPs with source='api' that are not in the API response
        global $wpdb;
        $table = $wpdb->prefix . VMPFence_Constants::TABLE_BLOCKED_IPS;
        
        // Get all active IPs with source='api' or 'both'
        $local_api_ips = $wpdb->get_results(
            "SELECT ip_address, source FROM {$table} WHERE is_active = 1 AND (source = 'api' OR source = 'both')",
            ARRAY_A
        );
        
        $stats['removed'] = 0;
        foreach ($local_api_ips as $local_ip) {
            $ip_addr = $local_ip['ip_address'];
            
            // If this IP is not in the API response, handle it based on source
            if (!in_array($ip_addr, $api_ips)) {
                if ($local_ip['source'] === 'api') {
                    // Pure API blocks that are gone from API should be deactivated
                    $wpdb->update(
                        $table,
                        array('is_active' => 0),
                        array('ip_address' => $ip_addr),
                        array('%d'),
                        array('%s')
                    );
                    $stats['removed']++;
                    VMPFence_Secure_Logger::info("Deactivated IP (removed from API)", ['ip' => $ip_addr]);
                } elseif ($local_ip['source'] === 'both') {
                    // If source was 'both', change back to 'local' (keep the block, just not synced)
                    $wpdb->update(
                        $table,
                        array('source' => 'local'),
                        array('ip_address' => $ip_addr),
                        array('%s'),
                        array('%s')
                    );
                    VMPFence_Secure_Logger::info("Changed IP source from 'both' to 'local' (removed from API)", ['ip' => $ip_addr]);
                }
            }
        }
        
        // Refresh license data after successful sync (ensures license key is up-to-date)
        $license_refreshed = false;
        if (class_exists('VMPFence_API_Client') && class_exists('VMPFence_License') && class_exists('VMPFence_Config')) {
            try {
                // Reuse existing $api_client and $api_key from sync_from_api scope
                $license_data = $api_client->check_api_key($api_key);
                if (!is_wp_error($license_data) && isset($license_data['license_key'])) {
                    VMPFence_License::update_license_settings($license_data);
                    $license_refreshed = true;
                }
            } catch (Exception $e) {
                // Silently fail - license refresh is not critical for sync operation
            }
        }
        
        $stats['license_refreshed'] = $license_refreshed;
        return $stats;
    }

    /**
     * Report local block to API
     *
     * @deprecated 2.0.1 This feature has been removed. Local IP blocking remains functional.
     * @since 1.0.0
     * @param string $ip IP address
     * @param string $reason Reason for blocking
     * @param int $duration_minutes Duration in minutes
     * @return bool Always returns false (feature disabled)
     */
    public static function report_to_api($ip, $reason, $duration_minutes = 60) {
        // Feature removed: IP reporting to API no longer supported
        // Local IP blocking continues to work normally
        VMPFence_Secure_Logger::info("report_to_api() called but feature is disabled", ['ip' => $ip]);
        return false;
    }

    /**
     * Cleanup expired blocks
     *
     * @since 1.0.0
     * @return int Number of blocks cleaned up
     */
    public static function cleanup_expired() {
        global $wpdb;
        
        $table = $wpdb->prefix . VMPFence_Constants::TABLE_BLOCKED_IPS;
        
        // Deactivate expired blocks (blocked_until > 0 AND blocked_until <= current time)
        $result = $wpdb->query($wpdb->prepare(
            "UPDATE {$table} 
             SET is_active = 0 
             WHERE is_active = 1 
             AND blocked_until > 0 
             AND blocked_until <= %d", // Expired if blocked_until is past current timestamp
            time() // Current Unix timestamp
        ));
        
        return $result !== false ? $result : 0;
    }

    /**
     * Get statistics
     *
     * @since 1.0.0
     * @return array Statistics
     */
    public static function get_stats() {
        global $wpdb;
        
        $table = $wpdb->prefix . VMPFence_Constants::TABLE_BLOCKED_IPS;
        
        return array(
            'total' => (int) $wpdb->get_var("SELECT COUNT(*) FROM {$table} WHERE is_active = 1"),
            'active' => (int) $wpdb->get_var($wpdb->prepare(
                "SELECT COUNT(*) FROM {$table} 
                 WHERE is_active = 1 
                 AND (blocked_until = 0 OR blocked_until > %d)", // 0 = permanent, timestamp = temporary
                time() // Current Unix timestamp
            )),
            'local' => (int) $wpdb->get_var("SELECT COUNT(*) FROM {$table} WHERE source = 'local' AND is_active = 1"),
            'api' => (int) $wpdb->get_var("SELECT COUNT(*) FROM {$table} WHERE source = 'api' AND is_active = 1"),
            'both' => (int) $wpdb->get_var("SELECT COUNT(*) FROM {$table} WHERE source = 'both' AND is_active = 1")
        );
    }
}
