<?php
/**
 * Whitelist - cac pattern an toan, bo qua khi phan tich
 */
if (!defined('ABSPATH')) exit;

class Foxblock_Whitelist
{
    /**
     * Cac ham nguy hiem nhung duoc dung hop le trong WP core/plugin noi tieng.
     * Key: ten ham, Value: danh sach ten file/path duoc phep.
     */
    public static $safe_function_contexts = array(
        'base64_decode' => array(
            'wp-includes/class-smtp.php',
            'wp-includes/class-phpmailer.php',
            'wp-includes/functions.php',
        ),
        'eval' => array(),
        'shell_exec' => array(),
    );

    /**
     * Thu muc runtime de giam noise khi scan toan bo website.
     * Van quet neu ben trong co file PHP va ban muon, nhung mac dinh nen bo qua cache/backups.
     */
    public static $runtime_dirs = array(
        'wp-content/cache',
        'wp-content/backups',
        'wp-content/updraft',
    );

    public static function normalize_path(string $rel_path): string
    {
        return ltrim(str_replace('\\', '/', $rel_path), '/');
    }

    public static function is_core_path(string $rel_path): bool
    {
        $rel_path = self::normalize_path($rel_path);

        if (strpos($rel_path, 'wp-admin/') === 0 || strpos($rel_path, 'wp-includes/') === 0) {
            return true;
        }

        return in_array($rel_path, array(
            'index.php',
            'wp-activate.php',
            'wp-blog-header.php',
            'wp-comments-post.php',
            'wp-config-sample.php',
            'wp-cron.php',
            'wp-links-opml.php',
            'wp-load.php',
            'wp-login.php',
            'wp-mail.php',
            'wp-settings.php',
            'wp-signup.php',
            'wp-trackback.php',
            'xmlrpc.php',
        ), true);
    }

    public static function is_runtime_path(string $rel_path): bool
    {
        $rel_path = self::normalize_path($rel_path);

        foreach (self::$runtime_dirs as $dir) {
            if (strpos($rel_path, $dir . '/') === 0) {
                return true;
            }
        }

        return false;
    }

    public static function is_own_plugin_path(string $rel_path): bool
    {
        $rel_path = self::normalize_path($rel_path);
        $plugin_dir = self::normalize_path(str_replace(wp_normalize_path(ABSPATH), '', wp_normalize_path(FOXBLOCK_PLUGIN_DIR)));

        return $plugin_dir !== '' && strpos($rel_path, $plugin_dir) === 0;
    }

    /**
     * Khong bo qua core nua. Chi bo qua mot so thu muc runtime rat on ao.
     */
    public static function is_skipped_path(string $rel_path): bool
    {
        return self::is_runtime_path($rel_path) || self::is_own_plugin_path($rel_path);
    }

    public static function is_safe_context(string $func_name, string $rel_path): bool
    {
        $func_lower = strtolower($func_name);
        $rel_path   = self::normalize_path($rel_path);

        if (!isset(self::$safe_function_contexts[$func_lower])) {
            return false;
        }

        foreach (self::$safe_function_contexts[$func_lower] as $safe_path) {
            if (strpos($rel_path, self::normalize_path($safe_path)) !== false) {
                return true;
            }
        }

        return false;
    }

    /**
     * Van report core, nhung dung nguong chat hon de tranh false positive.
     */
    public static function should_report_finding(string $rel_path, array $finding): bool
    {
        $score  = isset($finding['score']) ? (int) $finding['score'] : 0;
        $label  = strtolower((string) ($finding['label'] ?? ''));
        $method = strtolower((string) ($finding['method'] ?? ''));
        $risk   = strtolower((string) ($finding['risk'] ?? ''));

        if (!self::is_core_path($rel_path)) {
            return $score >= Foxblock_Analyzer::THRESHOLD_LOW;
        }

        if ($method === 'deobfuscated') {
            return true;
        }

        $high_confidence_patterns = array(
            'eval(base64_decode',
            'eval(gzinflate',
            'eval(str_rot13',
            'preg_replace /e',
            'include file tu url remote',
            'ghi file .php',
            'input nguoi dung',
        );

        foreach ($high_confidence_patterns as $pattern) {
            if (strpos($label, $pattern) !== false) {
                return true;
            }
        }

        if ($risk === 'high' && $score >= Foxblock_Analyzer::THRESHOLD_HIGH) {
            return true;
        }

        return false;
    }
}
