//! Anti-VM and Sandbox Detection
//!
//! Detects common virtualization artifacts to prevent
//! analysis in controlled environments.

/// Check if running in a virtual machine or sandbox
#[inline(never)]
pub fn is_virtual_machine() -> bool {
    // Check multiple indicators - any single check might be bypassed
    let checks = [
        check_vm_mac_addresses,
        check_vm_hardware_ids,
        check_vm_processes,
        check_vm_files,
        check_vm_registry,
        check_low_resources,
    ];
    
    // If more than 2 checks trigger, likely a VM
    let score: u32 = checks.iter()
        .map(|check| if check() { 1 } else { 0 })
        .sum();
    
    score >= 2
}

/// Check for known VM MAC address prefixes
fn check_vm_mac_addresses() -> bool {
    #[cfg(windows)]
    {
        // Get network adapter info and check MAC prefixes
        // VMware: 00:0C:29, 00:50:56
        // VirtualBox: 08:00:27
        // Hyper-V: 00:15:5D
        // Parallels: 00:1C:42
        
        // Simplified check via ipconfig output patterns
        if let Ok(output) = std::process::Command::new("ipconfig")
            .arg("/all")
            .output()
        {
            let stdout = String::from_utf8_lossy(&output.stdout).to_lowercase();
            let vm_macs = ["00-0c-29", "00-50-56", "08-00-27", "00-15-5d", "00-1c-42"];
            for mac in &vm_macs {
                if stdout.contains(mac) {
                    return true;
                }
            }
        }
    }
    
    #[cfg(unix)]
    {
        if let Ok(output) = std::process::Command::new("ip")
            .args(["link", "show"])
            .output()
        {
            let stdout = String::from_utf8_lossy(&output.stdout).to_lowercase();
            let vm_macs = ["00:0c:29", "00:50:56", "08:00:27", "00:15:5d", "00:1c:42"];
            for mac in &vm_macs {
                if stdout.contains(mac) {
                    return true;
                }
            }
        }
    }
    
    false
}

/// Check for VM-specific hardware IDs
fn check_vm_hardware_ids() -> bool {
    #[cfg(windows)]
    {
        // Check WMI for VM indicators
        let vm_indicators = [
            "vmware", "virtualbox", "vbox", "qemu", "xen", 
            "virtual", "hyperv", "parallels", "kvm"
        ];
        
        // Check computer name/model via WMI
        if let Ok(output) = std::process::Command::new("wmic")
            .args(["computersystem", "get", "model"])
            .output()
        {
            let stdout = String::from_utf8_lossy(&output.stdout).to_lowercase();
            for indicator in &vm_indicators {
                if stdout.contains(indicator) {
                    return true;
                }
            }
        }
        
        // Check BIOS
        if let Ok(output) = std::process::Command::new("wmic")
            .args(["bios", "get", "serialnumber"])
            .output()
        {
            let stdout = String::from_utf8_lossy(&output.stdout).to_lowercase();
            for indicator in &vm_indicators {
                if stdout.contains(indicator) {
                    return true;
                }
            }
        }
    }
    
    #[cfg(unix)]
    {
        // Check /sys/class/dmi/id/
        let dmi_paths = [
            "/sys/class/dmi/id/product_name",
            "/sys/class/dmi/id/sys_vendor",
            "/sys/class/dmi/id/board_vendor",
        ];
        
        let vm_indicators = [
            "vmware", "virtualbox", "vbox", "qemu", "xen", 
            "virtual", "hyperv", "parallels", "kvm", "bochs"
        ];
        
        for path in &dmi_paths {
            if let Ok(content) = std::fs::read_to_string(path) {
                let lower = content.to_lowercase();
                for indicator in &vm_indicators {
                    if lower.contains(indicator) {
                        return true;
                    }
                }
            }
        }
    }
    
    false
}

/// Check for VM-related processes
fn check_vm_processes() -> bool {
    let vm_processes = [
        "vmtoolsd", "vmwaretray", "vmwareuser",    // VMware
        "vboxservice", "vboxtray", "vboxclient",   // VirtualBox
        "xenservice",                               // Xen
        "qemu-ga",                                  // QEMU
        "prl_tools", "prl_cc",                     // Parallels
    ];
    
    #[cfg(windows)]
    {
        if let Ok(output) = std::process::Command::new("tasklist").output() {
            let stdout = String::from_utf8_lossy(&output.stdout).to_lowercase();
            for proc in &vm_processes {
                if stdout.contains(proc) {
                    return true;
                }
            }
        }
    }
    
    #[cfg(unix)]
    {
        if let Ok(output) = std::process::Command::new("ps")
            .args(["aux"])
            .output()
        {
            let stdout = String::from_utf8_lossy(&output.stdout).to_lowercase();
            for proc in &vm_processes {
                if stdout.contains(proc) {
                    return true;
                }
            }
        }
    }
    
    false
}

/// Check for VM-specific files
fn check_vm_files() -> bool {
    #[cfg(windows)]
    {
        let vm_files = [
            r"C:\Windows\System32\drivers\vmmouse.sys",
            r"C:\Windows\System32\drivers\vmhgfs.sys",
            r"C:\Windows\System32\drivers\VBoxMouse.sys",
            r"C:\Windows\System32\drivers\VBoxGuest.sys",
            r"C:\Windows\System32\drivers\VBoxSF.sys",
        ];
        
        for file in &vm_files {
            if std::path::Path::new(file).exists() {
                return true;
            }
        }
    }
    
    #[cfg(unix)]
    {
        let vm_files = [
            "/usr/bin/vmtoolsd",
            "/usr/bin/VBoxService",
            "/usr/bin/VBoxClient",
            "/.dockerenv",
            "/run/.containerenv",
        ];
        
        for file in &vm_files {
            if std::path::Path::new(file).exists() {
                return true;
            }
        }
    }
    
    false
}

/// Check Windows registry for VM indicators
fn check_vm_registry() -> bool {
    #[cfg(windows)]
    {
        // Check via reg query
        let registry_keys = [
            r"HKLM\SOFTWARE\VMware, Inc.\VMware Tools",
            r"HKLM\SOFTWARE\Oracle\VirtualBox Guest Additions",
        ];
        
        for key in &registry_keys {
            if let Ok(output) = std::process::Command::new("reg")
                .args(["query", key])
                .output()
            {
                if output.status.success() {
                    return true;
                }
            }
        }
    }
    
    false
}

/// Check for suspiciously low resources (sandbox indicator)
fn check_low_resources() -> bool {
    // Sandboxes often have minimal resources
    
    // Check CPU count
    let cpus = std::thread::available_parallelism()
        .map(|n| n.get())
        .unwrap_or(1);
    
    if cpus < 2 {
        return true;
    }
    
    // Check available disk space (simplified)
    #[cfg(windows)]
    {
        if let Ok(output) = std::process::Command::new("wmic")
            .args(["logicaldisk", "get", "size"])
            .output()
        {
            let stdout = String::from_utf8_lossy(&output.stdout);
            // Very small disk = sandbox
            if let Some(size_str) = stdout.lines().nth(1) {
                if let Ok(size) = size_str.trim().parse::<u64>() {
                    // Less than 50GB
                    if size < 50_000_000_000 {
                        return true;
                    }
                }
            }
        }
    }
    
    false
}

/// Check for analysis tools
pub fn check_analysis_tools() -> bool {
    let tools = [
        "wireshark", "fiddler", "burp", "charles",     // Network
        "x64dbg", "x32dbg", "ollydbg", "windbg",       // Debuggers
        "ida", "ida64", "ghidra", "radare2", "r2",     // Disassemblers
        "procmon", "procexp", "processhacker",          // Process monitors
        "pestudio", "die", "exeinfope",                // PE analyzers
    ];
    
    #[cfg(windows)]
    {
        if let Ok(output) = std::process::Command::new("tasklist").output() {
            let stdout = String::from_utf8_lossy(&output.stdout).to_lowercase();
            for tool in &tools {
                if stdout.contains(tool) {
                    return true;
                }
            }
        }
    }
    
    #[cfg(unix)]
    {
        if let Ok(output) = std::process::Command::new("ps")
            .args(["aux"])
            .output()
        {
            let stdout = String::from_utf8_lossy(&output.stdout).to_lowercase();
            for tool in &tools {
                if stdout.contains(tool) {
                    return true;
                }
            }
        }
    }
    
    false
}
