//! # VMProtect SDK 集成模块
//!
//! 提供 VMProtect SDK 的 FFI 绑定和便捷宏,
//! 用于在 Rust 代码中标记需要保护的代码区域。
//!
//! ## 使用方式
//!
//! ```no_run
//! use ethercat::vmp_protect;
//!
//! fn sensitive_function() {
//!     vmp_protect!("授权验证", Ultra, {
//!         // 关键代码 - 将被虚拟化+变异保护
//!     });
//! }
//! ```
//!
//! ## 保护级别
//!
//! | 级别 | 说明 | 适用场景 |
//! |------|------|----------|
//! | Mutation | 代码变异 | 一般保护, 性能影响小 |
//! | Virtualization | 代码虚拟化 | 中等保护, 有一定性能影响 |
//! | Ultra | 变异+虚拟化 | 最强保护, 适用于授权/加密 |
//!
//! ## 注意事项
//!
//! - VMProtect SDK DLL (VMProtectSDK64.dll) 必须在运行时可用
//! - 未找到 SDK DLL 时所有保护函数为空操作 (no-op), 不影响功能
//! - 编译时无需 VMProtect SDK, 仅运行时动态加载

use std::ffi::CString;
use std::sync::Once;

// === VMProtect SDK FFI 函数类型 ===

/// VMProtectBegin - 标记保护区域开始 (变异模式)
type VmpBeginFn = unsafe extern "C" fn(marker_name: *const i8);

/// VMProtectBeginVirtualization - 标记保护区域开始 (虚拟化模式)
type VmpBeginVirtualizationFn = unsafe extern "C" fn(marker_name: *const i8);

/// VMProtectBeginMutation - 标记保护区域开始 (变异模式)
type VmpBeginMutationFn = unsafe extern "C" fn(marker_name: *const i8);

/// VMProtectBeginUltra - 标记保护区域开始 (虚拟化+变异)
type VmpBeginUltraFn = unsafe extern "C" fn(marker_name: *const i8);

/// VMProtectEnd - 标记保护区域结束
type VmpEndFn = unsafe extern "C" fn();

/// VMProtectIsDebuggerPresent - 检测调试器
type VmpIsDebuggerPresentFn = unsafe extern "C" fn(check_kernel: i32) -> i32;

/// VMProtectIsVirtualMachinePresent - 检测虚拟机
type VmpIsVirtualMachinePresentFn = unsafe extern "C" fn() -> i32;

/// VMProtectDecryptStringA - 解密受保护的 ASCII 字符串
type VmpDecryptStringAFn = unsafe extern "C" fn(value: *const i8) -> *const i8;

/// VMProtectDecryptStringW - 解密受保护的 Unicode 字符串
type VmpDecryptStringWFn = unsafe extern "C" fn(value: *const u16) -> *const u16;

/// VMProtectFreeString - 释放解密后的字符串
type VmpFreeStringFn = unsafe extern "C" fn(value: *const std::ffi::c_void);

// === SDK 函数指针全局存储 ===

/// VMProtect SDK 函数指针集合
struct VmpSdk {
    begin: Option<VmpBeginFn>,
    begin_virtualization: Option<VmpBeginVirtualizationFn>,
    begin_mutation: Option<VmpBeginMutationFn>,
    begin_ultra: Option<VmpBeginUltraFn>,
    end: Option<VmpEndFn>,
    is_debugger_present: Option<VmpIsDebuggerPresentFn>,
    is_virtual_machine_present: Option<VmpIsVirtualMachinePresentFn>,
    decrypt_string_a: Option<VmpDecryptStringAFn>,
    decrypt_string_w: Option<VmpDecryptStringWFn>,
    free_string: Option<VmpFreeStringFn>,
    /// SDK 是否成功加载
    loaded: bool,
}

/// 全局 SDK 实例 (线程安全, 仅初始化一次)
static INIT: Once = Once::new();
static mut SDK: VmpSdk = VmpSdk {
    begin: None,
    begin_virtualization: None,
    begin_mutation: None,
    begin_ultra: None,
    end: None,
    is_debugger_present: None,
    is_virtual_machine_present: None,
    decrypt_string_a: None,
    decrypt_string_w: None,
    free_string: None,
    loaded: false,
};

/// 加载 VMProtect SDK DLL 并解析函数指针
///
/// 自动搜索以下路径:
/// 1. 当前进程目录
/// 2. PATH 环境变量
/// 3. 系统目录
fn load_sdk() {
    // 小辅助: obfstr! 解出明文 + 末尾追加 NUL → Vec<u8> 给 libloading::get 用.
    // 编译期 XOR 混淆, 反编译看不到符号明文.
    #[inline(always)]
    fn sym(s: &str) -> Vec<u8> {
        let mut v = s.as_bytes().to_vec();
        v.push(0);
        v
    }

    INIT.call_once(|| {
        // Windows: VMProtectSDK64.dll, Linux: libVMProtectSDK.so
        // (DLL 名通过 obfstr! 编译期混淆隐藏)
        #[cfg(target_os = "windows")]
        let dll_name = obfstr::obfstr!("VMProtectSDK64.dll").to_string();
        #[cfg(target_os = "linux")]
        let dll_name = obfstr::obfstr!("libVMProtectSDK.so").to_string();
        #[cfg(not(any(target_os = "windows", target_os = "linux")))]
        let dll_name = obfstr::obfstr!("libVMProtectSDK.so").to_string();

        // 使用 libloading 动态加载
        let lib = match unsafe { libloading::Library::new(&dll_name) } {
            Ok(lib) => lib,
            Err(_) => {
                // SDK 不可用 - 所有函数为空操作
                return;
            }
        };

        unsafe {
            // 解析各函数指针 (失败时保持 None); 符号名 obfstr 混淆.
            SDK.begin = lib
                .get::<VmpBeginFn>(&sym(obfstr::obfstr!("VMProtectBegin")))
                .ok()
                .map(|f| *f);
            SDK.begin_virtualization = lib
                .get::<VmpBeginVirtualizationFn>(&sym(obfstr::obfstr!("VMProtectBeginVirtualization")))
                .ok()
                .map(|f| *f);
            SDK.begin_mutation = lib
                .get::<VmpBeginMutationFn>(&sym(obfstr::obfstr!("VMProtectBeginMutation")))
                .ok()
                .map(|f| *f);
            SDK.begin_ultra = lib
                .get::<VmpBeginUltraFn>(&sym(obfstr::obfstr!("VMProtectBeginUltra")))
                .ok()
                .map(|f| *f);
            SDK.end = lib
                .get::<VmpEndFn>(&sym(obfstr::obfstr!("VMProtectEnd")))
                .ok()
                .map(|f| *f);
            SDK.is_debugger_present = lib
                .get::<VmpIsDebuggerPresentFn>(&sym(obfstr::obfstr!("VMProtectIsDebuggerPresent")))
                .ok()
                .map(|f| *f);
            SDK.is_virtual_machine_present = lib
                .get::<VmpIsVirtualMachinePresentFn>(&sym(obfstr::obfstr!("VMProtectIsVirtualMachinePresent")))
                .ok()
                .map(|f| *f);
            SDK.decrypt_string_a = lib
                .get::<VmpDecryptStringAFn>(&sym(obfstr::obfstr!("VMProtectDecryptStringA")))
                .ok()
                .map(|f| *f);
            SDK.decrypt_string_w = lib
                .get::<VmpDecryptStringWFn>(&sym(obfstr::obfstr!("VMProtectDecryptStringW")))
                .ok()
                .map(|f| *f);
            SDK.free_string = lib
                .get::<VmpFreeStringFn>(&sym(obfstr::obfstr!("VMProtectFreeString")))
                .ok()
                .map(|f| *f);

            SDK.loaded = true;

            // 防止库被卸载 (函数指针需要始终有效)
            std::mem::forget(lib);
        }
    });
}

// === 公开 API ===

/// 获取 SDK 是否已加载
pub fn is_sdk_loaded() -> bool {
    load_sdk();
    unsafe { SDK.loaded }
}

/// 标记保护区域开始 (通用模式)
pub fn vmp_begin(marker: &str) {
    load_sdk();
    if let Some(f) = unsafe { SDK.begin } {
        if let Ok(name) = CString::new(marker) {
            unsafe { f(name.as_ptr()) };
        }
    }
}

/// 标记保护区域开始 (虚拟化模式)
pub fn vmp_begin_virtualization(marker: &str) {
    load_sdk();
    if let Some(f) = unsafe { SDK.begin_virtualization } {
        if let Ok(name) = CString::new(marker) {
            unsafe { f(name.as_ptr()) };
        }
    }
}

/// 标记保护区域开始 (变异模式)
pub fn vmp_begin_mutation(marker: &str) {
    load_sdk();
    if let Some(f) = unsafe { SDK.begin_mutation } {
        if let Ok(name) = CString::new(marker) {
            unsafe { f(name.as_ptr()) };
        }
    }
}

/// 标记保护区域开始 (Ultra: 虚拟化+变异)
pub fn vmp_begin_ultra(marker: &str) {
    load_sdk();
    if let Some(f) = unsafe { SDK.begin_ultra } {
        if let Ok(name) = CString::new(marker) {
            unsafe { f(name.as_ptr()) };
        }
    }
}

/// 标记保护区域结束
pub fn vmp_end() {
    load_sdk();
    if let Some(f) = unsafe { SDK.end } {
        unsafe { f() };
    }
}

/// 检测调试器
///
/// # 参数
/// - `check_kernel`: 是否检测内核调试器 (如 WinDbg)
///
/// # 返回
/// - `true`: 检测到调试器
/// - `false`: 未检测到调试器, 或 SDK 不可用
pub fn is_debugger_present(check_kernel: bool) -> bool {
    load_sdk();
    if let Some(f) = unsafe { SDK.is_debugger_present } {
        unsafe { f(if check_kernel { 1 } else { 0 }) != 0 }
    } else {
        false
    }
}

/// 检测虚拟机环境
///
/// # 返回
/// - `true`: 运行在虚拟机中 (VMware, VirtualBox, Hyper-V 等)
/// - `false`: 未检测到虚拟机, 或 SDK 不可用
pub fn is_virtual_machine() -> bool {
    load_sdk();
    if let Some(f) = unsafe { SDK.is_virtual_machine_present } {
        unsafe { f() != 0 }
    } else {
        false
    }
}

/// 解密受保护的字符串 (ASCII)
///
/// VMProtect 会在编译时加密标记的字符串常量,
/// 运行时通过此函数解密。
///
/// # 安全性
/// 返回的字符串在下次调用时可能失效, 应立即使用。
pub fn decrypt_string(value: &str) -> String {
    load_sdk();
    if let Some(f) = unsafe { SDK.decrypt_string_a } {
        if let Ok(cstr) = CString::new(value) {
            let decrypted = unsafe { f(cstr.as_ptr()) };
            if !decrypted.is_null() {
                let result = unsafe { std::ffi::CStr::from_ptr(decrypted) }
                    .to_string_lossy()
                    .into_owned();
                // 释放 VMProtect 分配的内存
                if let Some(free_fn) = unsafe { SDK.free_string } {
                    unsafe { free_fn(decrypted as *const std::ffi::c_void) };
                }
                return result;
            }
        }
    }
    // SDK 不可用时返回原始字符串
    value.to_string()
}

/// 反调试检查 - 检测到调试器时执行指定操作
///
/// # 用法
/// ```no_run
/// use ethercat::protection;
/// protection::anti_debug_check(true, || {
///     eprintln!("检测到调试器, 程序退出");
///     std::process::exit(1);
/// });
/// ```
pub fn anti_debug_check<F: FnOnce()>(check_kernel: bool, on_detected: F) {
    if is_debugger_present(check_kernel) {
        on_detected();
    }
}

/// 反虚拟机检查 - 检测到虚拟机时执行指定操作
///
/// # 用法
/// ```no_run
/// use ethercat::protection;
/// protection::anti_vm_check(|| {
///     eprintln!("不支持在虚拟机中运行");
///     std::process::exit(1);
/// });
/// ```
pub fn anti_vm_check<F: FnOnce()>(on_detected: F) {
    if is_virtual_machine() {
        on_detected();
    }
}

// === 宏定义 ===

/// 保护代码块宏 - 自动在代码块前后插入 VMProtect 标记
///
/// # 用法
///
/// ```no_run
/// use ethercat::vmp_protect;
///
/// // Ultra 保护 (虚拟化+变异) - 用于授权/加密
/// let result = vmp_protect!("授权验证", Ultra, {
///     verify_license_key(key)
/// });
///
/// // Mutation 保护 (变异) - 用于一般逻辑
/// vmp_protect!("PDO处理", Mutation, {
///     process_pdo_data(data);
/// });
///
/// // Virtualization 保护 (虚拟化) - 用于关键算法
/// vmp_protect!("密钥派生", Virtualization, {
///     derive_key(salt, password)
/// });
/// ```
#[macro_export]
macro_rules! vmp_protect {
    ($marker:expr, Ultra, $body:block) => {{
        $crate::utils::protection::vmp_begin_ultra($marker);
        let __vmp_result = (|| $body)();
        $crate::utils::protection::vmp_end();
        __vmp_result
    }};
    ($marker:expr, Mutation, $body:block) => {{
        $crate::utils::protection::vmp_begin_mutation($marker);
        let __vmp_result = (|| $body)();
        $crate::utils::protection::vmp_end();
        __vmp_result
    }};
    ($marker:expr, Virtualization, $body:block) => {{
        $crate::utils::protection::vmp_begin_virtualization($marker);
        let __vmp_result = (|| $body)();
        $crate::utils::protection::vmp_end();
        __vmp_result
    }};
}
