<?php
defined('ABSPATH') || exit;

// In engines/pattern.php:
function wpsec_load_malware_patterns() {
    // Get patterns from local cache or API
    $patterns = wpsec_get_pattern_database();
    
    if ($patterns) {
        $patterns['source'] = 'external';
        wpsec_debug_log('🌐 Using EXTERNAL pattern database', 'info');
    } else {
        // Fallback to bundled patterns
        $patterns = [
            'php' => wpsec_get_bundled_php_patterns(),
            'js' => wpsec_get_bundled_js_patterns(),
            'html' => wpsec_get_bundled_html_patterns(),
            'source' => 'local'
        ];
        wpsec_debug_log('📦 Using LOCAL bundled patterns', 'info');
    }
    
    return $patterns;
}

function wpsec_get_bundled_php_patterns() {
    return [
        [
            'id' => 'php_eval_base64',
            'pattern' => '/eval\s*\(\s*base64_decode\s*\(/i',
            'name' => 'Base64 Encoded Eval',
            'severity' => 'critical',
            'confidence' => 90,
            'description' => 'Obfuscated PHP code using base64_decode with eval()',
            'exclude_patterns' => [
                '/\/wp-content\/plugins\/wordfence\//i',
                '/\/wp-content\/plugins\/sucuri-scanner\//i',
                '/\/wp-content\/plugins\/wpfortai-security\//i',
                '/\/wp-content\/plugins\/wpfortai-security\//i'
            ]
        ],
        [
            'id' => 'php_gzinflate_eval',
            'pattern' => '/eval\s*\(\s*gzinflate\s*\(/i',
            'name' => 'Gzinflate Encoded Eval',
            'severity' => 'critical',
            'confidence' => 90,
            'description' => 'Obfuscated PHP code using gzinflate with eval()',
            'exclude_patterns' => [
                '/\/wp-content\/plugins\/wpfortai-security\//i',
                '/\/wp-content\/plugins\/wpfortai-security\//i'
            ]
        ],
        [
            'id' => 'php_backdoor_functions',
            'pattern' => '/(\$_POST|\$_GET|\$_REQUEST|\$_COOKIE)\s*\[\s*[\'"](?:cmd|command|shell|exec|system|passthru)\s*[\'"]\s*\]/i',
            'name' => 'Command Execution Backdoor',
            'severity' => 'critical',
            'confidence' => 95,
            'description' => 'Code that allows remote command execution',
            'exclude_patterns' => [
                '/\/wp-content\/plugins\/wpfortai-security\//i',
                '/\/wp-content\/plugins\/wpfortai-security\//i'
            ]
        ],
        [
            'id' => 'php_webshell_keywords',
            'pattern' => '/(c99|r57|web[\s-]*shell|b374k|weevely|php[\s-]*shell|shell\.php)/i',
            'name' => 'Web Shell Keywords',
            'severity' => 'critical',
            'confidence' => 85,
            'description' => 'Known web shell keywords detected',
            'exclude_patterns' => [
                '/\/wp-content\/plugins\/wpfortai-security\//i',
                '/\/wp-content\/plugins\/wpfortai-security\//i'
            ]
        ],
        [
            'id' => 'php_suspicious_encoding',
            'pattern' => '/(preg_replace\s*\(\s*[\'"]\/\.\*\/e[\'"]|create_function\s*\(\s*[\'"]\$[\'"])/i',
            'name' => 'Suspicious Code Execution',
            'severity' => 'critical',
            'confidence' => 90,
            'description' => 'Code that uses dangerous PHP functions for dynamic execution',
            'exclude_patterns' => [
                '/\/wp-content\/plugins\/wpfortai-security\//i',
                '/\/wp-content\/plugins\/wpfortai-security\//i'
            ]
        ],
        [
            'id' => 'php_malicious_iframe',
            'pattern' => '/(<iframe|\$_GLOBALS\[.{1,30}\])\s*=\s*[\'"]https?:\/\/[^\'"\s]+[\'"];/i',
            'name' => 'Malicious iFrame Injection',
            'severity' => 'high',
            'confidence' => 85,
            'description' => 'Code that injects iframes into pages',
            'exclude_patterns' => [
                '/\/wp-content\/plugins\/wpfortai-security\//i',
                '/\/wp-content\/plugins\/wpfortai-security\//i'
            ]
        ],
        [
            'id' => 'php_htaccess_injection',
            'pattern' => '/(RewriteEngine|RewriteRule|RewriteCond|AddHandler|SetHandler|AddType|php_value|php_flag)/i',
            'name' => 'Suspicious .htaccess Rules',
            'severity' => 'medium',
            'confidence' => 75,
            'description' => 'Suspicious Apache configuration directives',
            'exclude_patterns' => [
                '/\/wp-content\/plugins\/wpfortai-security\//i',
                '/\/wp-content\/plugins\/wpfortai-security\//i'
            ]
        ],
        [
            'id' => 'php_malicious_redirect',
            'pattern' => '/(header\s*\(\s*[\'"]Location:\s*https?:\/\/|window\.location\.href\s*=\s*[\'"]https?:\/\/)/i',
            'name' => 'Suspicious Redirect',
            'severity' => 'high',
            'confidence' => 80,
            'description' => 'Code that performs suspicious redirects',
            'exclude_patterns' => [
                '/\/wp-content\/plugins\/wpfortai-security\//i',
                '/\/wp-content\/plugins\/wpfortai-security\//i'
            ]
        ],
        [
            'id' => 'php_file_upload',
            'pattern' => '/(move_uploaded_file\s*\(|copy\s*\(|file_put_contents\s*\()/i',
            'name' => 'File Upload Handler',
            'severity' => 'medium',
            'confidence' => 70,
            'description' => 'Code that handles file uploads',
            'exclude_patterns' => [
                '/\/wp-content\/plugins\/wpfortai-security\//i',
                '/\/wp-content\/plugins\/wpfortai-security\//i'
            ]
        ],
        [
            'id' => 'php_spam_seo',
            'pattern' => '/(<a\s+href=|window\.location\.replace\s*\()\s*[\'"]https?:\/\/[^\'"\s]+(viagra|casino|pharmacy|pills|poker|bet|gambling)[^\'"\s]*[\'"];/i',
            'name' => 'SEO Spam Links',
            'severity' => 'medium',
            'confidence' => 85,
            'description' => 'Spam SEO link injection',
            'exclude_patterns' => [
                '/\/wp-content\/plugins\/wpfortai-security\//i',
                '/\/wp-content\/plugins\/wpfortai-security\//i'
            ]
        ]
    ];
}

function wpsec_get_bundled_js_patterns() {
    return [
        [
            'id' => 'js_encoded_function',
            'pattern' => '/new\s+Function\s*\(\s*[\'"]return\s+this[\'"]\s*\)/i',
            'name' => 'Encoded Function Constructor',
            'severity' => 'medium',
            'confidence' => 50,
            'description' => 'Use of Function constructor with string parameter',
            'exclude_patterns' => [
                '/webpack|elementor|jquery|react|vue|angular/i'
            ],
            'context_length' => 100
        ],
        [
            'id' => 'js_iframe_inject',
            'pattern' => '/document\.write\s*\(\s*[\'"]<iframe\s+src=[\'"]https?:\/\//i',
            'name' => 'Hidden iFrame Injection',
            'severity' => 'high',
            'confidence' => 85,
            'description' => 'Code that injects hidden iframes into the page',
            'exclude_patterns' => [
                '/\/wp-content\/plugins\/wpfortai-security\//i',
                '/\/wp-content\/plugins\/wpfortai-security\//i'
            ]
        ],
        [
            'id' => 'js_cryptocurrency_miner',
            'pattern' => '/(CoinHive|coinhive\.com|coinhive\.min\.js|CoinHive\.Anonymous|crypto-?(?:night|loot)|minero\.cc|webmine\.pro)/i',
            'name' => 'Cryptocurrency Miner',
            'severity' => 'critical',
            'confidence' => 95,
            'description' => 'JavaScript cryptocurrency miner',
            'exclude_patterns' => [
                '/\/wp-content\/plugins\/wpfortai-security\//i',
                '/\/wp-content\/plugins\/wpfortai-security\//i'
            ]
        ],
        [
            'id' => 'js_malicious_redirect',
            'pattern' => '/(window\.location(?:\.href)?\s*=|document\.location(?:\.href)?\s*=|location\.replace\s*\()\s*[\'"]https?:\/\/[^\'"\s]+[\'"];/i',
            'name' => 'Suspicious Redirect',
            'severity' => 'high',
            'confidence' => 85,
            'description' => 'JavaScript code that performs suspicious redirects',
            'exclude_patterns' => [
                '/\/wp-content\/plugins\/wpfortai-security\//i',
                '/\/wp-content\/plugins\/wpfortai-security\//i'
            ]
        ],
        [
            'id' => 'js_eval_decode',
            'pattern' => '/eval\s*\(\s*(atob\s*\(|decodeURIComponent\s*\(|String\.fromCharCode|unescape\s*\()/i',
            'name' => 'Obfuscated JavaScript',
            'severity' => 'high',
            'confidence' => 80,
            'description' => 'Potentially malicious obfuscated JavaScript code',
            'exclude_patterns' => [
                '/\/wp-content\/plugins\/wpfortai-security\//i',
                '/\/wp-content\/plugins\/wpfortai-security\//i'
            ]
        ],
        [
            'id' => 'js_dom_manipulation',
            'pattern' => '/(document\.body\.appendChild|document\.createElement\s*\(\s*[\'"]script[\'"]\s*\)|document\.write\s*\()/i',
            'name' => 'Suspicious DOM Manipulation',
            'severity' => 'medium',
            'confidence' => 75,
            'description' => 'Code that dynamically injects content into the page',
            'exclude_patterns' => [
                '/\/wp-content\/plugins\/wpfortai-security\//i',
                '/\/wp-content\/plugins\/wpfortai-security\//i'
            ]
        ]
    ];
}

function wpsec_get_bundled_html_patterns() {
    // Common HTML malware patterns
    return [
        [
            'id' => 'html_hidden_iframe',
            'pattern' => '/<iframe[^>]+style\s*=\s*[\'"][^\'"]*(display\s*:\s*none|height\s*:\s*0|width\s*:\s*0)[^\'"]*[\'"]/i',
            'name' => 'Hidden iFrame',
            'severity' => 'high',
            'confidence' => 80,
            'description' => 'Hidden iframe that may load malicious content',
            'exclude_patterns' => [
                '/\/wp-content\/plugins\/wpfortai-security\//i',
                '/\/wp-content\/plugins\/wpfortai-security\//i'
            ]
        ],
        // More patterns from original file...
    ];
}

function wpsec_check_file_patterns($file_path, $patterns, $ext, $force_deep_scan = false) {
    // Skip files that don't exist
    if (!file_exists($file_path)) {
        return [];
    }
    
    // Early exit for our own plugin files to prevent self-flagging
    if (function_exists('wpsec_is_file_whitelisted') && wpsec_is_file_whitelisted($file_path)) {
        return [];
    }
    
    // Check if this is a test file for enhanced logging
    $is_test_file = (stripos($file_path, 'test-pattern') !== false || 
                    stripos($file_path, 'test-') !== false || 
                    stripos($file_path, 'eicar') !== false);
    $is_deep_scan = get_option('wpsec_deep_scan_mode', false);
    
    if ($is_test_file || $is_deep_scan) {
        wpsec_debug_log("🔍 PATTERN ENGINE: Starting pattern check for $file_path", 'info');
    }
    
    // Get the global verbose logging flag
    global $wpsec_verbose_logging;
    
    // Log every file scan when verbose logging is enabled
    if (!empty($wpsec_verbose_logging)) {
        wpsec_debug_log("🔎 SCAN FILE: Pattern engine checking file: $file_path", 'info');
    }
    
    // Check if we're in force deep scan mode
    global $wpsec_force_deep_scan;
    $force_deep_scan = $force_deep_scan || !empty($wpsec_force_deep_scan);
    
    // Generate cache key based on file hash
    $file_hash = md5_file($file_path);
    $cache_key = 'wpsec_pattern_' . $file_hash;
    
    if ($is_test_file || $is_deep_scan) {
        wpsec_debug_log("🔍 PATTERN ENGINE: File hash: $file_hash, Extension: $ext", 'info');
    }
    
    // Prepare cache logic
    $use_cache = !$force_deep_scan;
    $cached_result = false;
    
    // Always bypass cache in force deep scan mode
    if (!$use_cache) {
        // Delete existing cache entries
        delete_transient($cache_key);
        wpsec_debug_log("🔄 PATTERN ENGINE: Deep scan enabled, bypassing cache for: $file_path", 'info');
        if ($is_test_file) {
            wpsec_debug_log("🔥 PATTERN ENGINE: Deep scan - bypassing and clearing cache for: " . basename($file_path), 'info');
        }
    } else {
        // Check cache in normal scan mode, but only for existing files
        // This ensures new files are always scanned regardless of cache
        if (file_exists($file_path)) {
            $cached_result = get_transient($cache_key);
            if ($cached_result !== false) {
                wpsec_debug_log("💾 PATTERN ENGINE: Using cached result for: $file_path", 'info');
                return $cached_result;
            }
        }
    }
    
    // Try direct file access first
    $file_content = @file_get_contents($file_path);
    
    // If direct access fails, try WP_Filesystem
    if ($file_content === false) {
        // Initialize WP_Filesystem if needed
        if (!function_exists('WP_Filesystem')) {
            require_once ABSPATH . 'wp-admin/includes/file.php';
        }
        
        // Try to initialize with direct method
        if (WP_Filesystem(false, false, true)) {
            global $wp_filesystem;
            if ($wp_filesystem && $wp_filesystem->exists($file_path)) {
                $file_content = $wp_filesystem->get_contents($file_path);
            }
        }
    }
    
    // If still can't read file, log and return empty
    if (!$file_content) {
        wpsec_debug_log("⚠️ Could not read file: " . $file_path, 'warning');
        return [];
    }
    
    $all_results = [];
    
    // First check the patterns for the current file extension
    $pattern_set = [];
    if (isset($patterns[$ext])) {
        $pattern_set = $patterns[$ext];
    } elseif ($ext == 'htm') {
        $pattern_set = $patterns['html'];
    } elseif (in_array($ext, ['phtml', 'inc'])) {
        $pattern_set = $patterns['php'];
    }
    
    $results = wpsec_check_with_pattern_set($file_path, $file_content, $pattern_set);
    if (!empty($results)) {
        $all_results = array_merge($all_results, $results);
    }
    
    // For PHP files, also check for embedded JavaScript malware
    if ($ext == 'php' && isset($patterns['js'])) {
        $js_results = wpsec_check_with_pattern_set($file_path, $file_content, $patterns['js']);
        if (!empty($js_results)) {
            $all_results = array_merge($all_results, $js_results);
        }
    }
    
    if (!empty($all_results)) {
        wpsec_debug_log("🔍 Found " . count($all_results) . " pattern matches in " . $file_path, 'info');
        foreach ($all_results as $result) {
            wpsec_debug_log("  - " . $result['name'] . " (" . $result['severity'] . ", " . $result['confidence'] . "%)", 'info');
        }
        
        if ($is_test_file || $is_deep_scan) {
            wpsec_debug_log("✅ PATTERN ENGINE: Found " . count($all_results) . " pattern detections in $file_path", 'info');
        }
    } else {
        if ($is_test_file || $is_deep_scan) {
            wpsec_debug_log("❌ PATTERN ENGINE: No pattern matches found in $file_path", 'error');
        }
    }
    
    // Cache results if not in deep scan mode
    global $wpsec_force_deep_scan, $wpsec_verbose_logging;
    
    // In deep scan mode, we never cache results
    if (!empty($wpsec_force_deep_scan)) {
        // Actively delete any existing cache for this file
        delete_transient($cache_key);
        
        if (!empty($wpsec_verbose_logging)) {
            wpsec_debug_log("🔥 PATTERN ENGINE: Deep scan - bypassing and clearing cache for: " . basename($file_path), 'info');
        }
    } 
    // In normal scan mode, cache the results
    else if (!empty($file_hash)) {
        $cache_duration = empty($all_results) ? DAY_IN_SECONDS : (6 * HOUR_IN_SECONDS);
        set_transient($cache_key, $all_results, $cache_duration);
        
        if (!empty($wpsec_verbose_logging)) {
            wpsec_debug_log("💾 PATTERN ENGINE: Caching results for: " . basename($file_path) . " (" . (empty($all_results) ? "clean" : "infected") . ")", 'info');
        }
    }
    
    return $all_results;
}

function wpsec_check_with_pattern_set($file_path, $file_content, $pattern_set) {
    $results = [];
    
    foreach ($pattern_set as $pattern) {
        // Validate and prepare exclude patterns
        if (!empty($pattern['exclude_patterns'])) {
            $valid_excludes = [];
            foreach ($pattern['exclude_patterns'] as $exclude) {
                // Ensure pattern is properly delimited
                if (!@preg_match($exclude, '')) {
                    // If pattern is invalid, try to fix it
                    $exclude = '/' . preg_quote(trim($exclude, '/'), '/') . '/i';
                }
                if (@preg_match($exclude, '') !== false) {
                    $valid_excludes[] = $exclude;
                }
            }
            
            // Check exclusions
            foreach ($valid_excludes as $exclude) {
                if (@preg_match($exclude, $file_path)) {
                    continue 2;
                }
            }
        }

        // Validate and prepare main pattern
        $search_pattern = $pattern['pattern'];
        if (!@preg_match($search_pattern, '')) {
            // If pattern is invalid, try to fix it
            $search_pattern = '/' . preg_quote(trim($search_pattern, '/'), '/') . '/i';
        }
        
        // Skip if pattern is still invalid
        if (@preg_match($search_pattern, '') === false) {
            wpsec_debug_log("Invalid pattern skipped: " . $pattern['id'], 'info');
            continue;
        }

        if (@preg_match_all($search_pattern, $file_content, $matches, PREG_OFFSET_CAPTURE)) {
            foreach ($matches[0] as $match) {
                $pos = $match[1];
                $matched_text = $match[0];
                
                // Get surrounding context with length limit
                $context_length = isset($pattern['context_length']) ? $pattern['context_length'] : 200;
                $context_start = max(0, $pos - ($context_length / 2));
                $context = substr($file_content, $context_start, $context_length);
                
                // Calculate file hash if not already done
                $file_hash = md5_file($file_path);
                
                $results[] = [
                    'type' => 'pattern',
                    'pattern_id' => $pattern['id'],
                    'name' => $pattern['name'],
                    'severity' => $pattern['severity'],
                    'confidence' => $pattern['confidence'],
                    'description' => $pattern['description'],
                    'match' => $matched_text,
                    'context' => $context,
                    'position' => $pos,
                    'score' => null,
                    'file_hash' => $file_hash,
                    'file_path' => $file_path,
                    'pattern' => $pattern['name'] // Include pattern name for consistent schema
                ];
            }
        }
    }
    
    return $results;
}