//! Anti-VM and Sandbox Detection - Redesigned
//!
//! Smart heuristic approach to detect analysis environments
//! without blocking production VPS servers

/// Check if running in a sandbox/analysis environment
/// Uses weighted scoring to avoid false positives on production VPS
#[inline(never)]
pub fn is_virtual_machine() -> bool {
    let mut score = 0;
    
    // HIGH risk indicators (2 points each)
    if check_analysis_tools() { score += 2; }
    if check_sandbox_artifacts() { score += 2; }
    
    // MEDIUM risk (1 point each)
    if check_low_resources() { score += 1; }
    if check_suspicious_environment() { score += 1; }
    
    // Threshold: 4+ points = very likely sandbox
    // Production VPS: max 1-2 points
    // Analysis sandbox: 4+ points (2 HIGH or 1 HIGH + 2 MEDIUM)
    score >= 4
}

/// HIGH: Check for reverse engineering tools in memory
pub fn check_analysis_tools() -> bool {
    #[cfg(unix)]
    {
        if let Ok(output) = std::process::Command::new("ps")
            .args(["aux"])
            .output()
        {
            let stdout = String::from_utf8_lossy(&output.stdout).to_lowercase();
            let tools = [
                "gdb", "lldb", "strace", "ltrace", "radare2", "r2", 
                "ida", "ida64", "x64dbg", "ghidra", "binaryninja",
                "frida-server", "rizin", "cutter", "hopper",
                "qemu-user"  // QEMU user-mode for cross-arch analysis
            ];
            
            for tool in &tools {
                if stdout.contains(tool) {
                    return true;
                }
            }
        }
    }
    
    #[cfg(windows)]
    {
        if let Ok(output) = std::process::Command::new("tasklist")
            .output()
        {
            let stdout = String::from_utf8_lossy(&output.stdout).to_lowercase();
            let tools = [
                "x64dbg", "x32dbg", "ollydbg", "windbg", "ida", "ida64",
                "ghidra", "binaryninja", "pestudio", "processhacker",
                "procmon", "procexp", "wireshark", "fiddler"
            ];
            
            for tool in &tools {
                if stdout.contains(tool) {
                    return true;
                }
            }
        }
    }
    
    false
}

/// HIGH: Sandbox-specific artifacts
fn check_sandbox_artifacts() -> bool {
    #[cfg(unix)]
    {
        // Wine (used for Windows malware analysis on Linux)
        let wine_paths = ["/tmp/.wine-", "/tmp/.X11-unix"];
        for path in &wine_paths {
            if std::fs::read_dir(path).is_ok() {
                return true;
            }
        }
    }
    
    false
}

/// MEDIUM: Suspicious environment variables
fn check_suspicious_environment() -> bool {
    let suspicious = [
        "WINE_",
        "QEMU_",
        "SANDBOX_",
        "AFL_",  // American Fuzzy Lop fuzzer
        "ASAN_",  // AddressSanitizer
    ];
    
    for (key, _) in std::env::vars() {
        for pattern in &suspicious {
            if key.starts_with(pattern) {
                return true;
            }
        }
    }
    
    false
}

/// MEDIUM: Very low resources (< 1GB RAM or 1 CPU)
fn check_low_resources() -> bool {
    // Single CPU = very suspicious
    let cpu_count = num_cpus::get();
    if cpu_count < 2 {
        return true;
    }
    
    // Check available memory
    #[cfg(unix)]
    {
        if let Ok(meminfo) = std::fs::read_to_string("/proc/meminfo") {
            for line in meminfo.lines() {
                if line.starts_with("MemTotal:") {
                    if let Some(kb_str) = line.split_whitespace().nth(1) {
                        if let Ok(kb) = kb_str.parse::<u64>() {
                            let mb = kb / 1024;
                            // Less than 1GB = sandbox
                            return mb < 1024;
                        }
                    }
                }
            }
        }
    }
    
    #[cfg(windows)]
    {
        use std::mem::MaybeUninit;
        unsafe {
            let mut mem_status = MaybeUninit::<winapi::um::sysinfoapi::MEMORYSTATUSEX>::uninit();
            let mem_status_ptr = mem_status.as_mut_ptr();
            (*mem_status_ptr).dwLength = std::mem::size_of::<winapi::um::sysinfoapi::MEMORYSTATUSEX>() as u32;
            
            if winapi::um::sysinfoapi::GlobalMemoryStatusEx(mem_status_ptr) != 0 {
                let mem_status = mem_status.assume_init();
                let total_mb = mem_status.ullTotalPhys / (1024 * 1024);
                return total_mb < 1024;
            }
        }
    }
    
    false
}
