// Auto-generated standalone executable for: simple
// Generated by ts-native standalone generator

use std::ffi::{c_void, CString};
use std::os::windows::ffi::OsStrExt;
use std::ptr;

#[link(name = "kernel32")]
extern "system" {
    fn LoadLibraryW(lp_lib_file_name: *const u16) -> *mut c_void;
    fn GetProcAddress(h_module: *mut c_void, lp_proc_name: *const i8) -> *mut c_void;
    fn FreeLibrary(h_lib_module: *mut c_void) -> i32;
    fn VirtualAlloc(lpAddress: *mut c_void, dwSize: usize, flAllocationType: u32, flProtect: u32) -> *mut c_void;
    fn VirtualFree(lpAddress: *mut c_void, dwSize: usize, dwFreeType: u32) -> i32;
    fn GetModuleFileNameW(hModule: *mut c_void, lpFilename: *mut u16, nSize: u32) -> u32;
}

const MEM_COMMIT: u32 = 0x1000;
const MEM_RESERVE: u32 = 0x2000;
const MEM_RELEASE: u32 = 0x8000;
const PAGE_EXECUTE_READWRITE: u32 = 0x40;
const PAGE_READWRITE: u32 = 0x04;

#[repr(C)]
struct Symbol {
    section: u8,
    offset: u32,
    name: [u8; 64],
}

#[repr(C)]
struct Relocation {
    section: u8,
    offset: u32,
    type_: u8,
    _padding: u8,
    target_name: [u8; 64],
}

static CODE: [u8; 40] = [
    0x55, 0x48, 0x89, 0xE5, 0x48, 0x83, 0xEC, 0x10, 0x48, 0x89, 0x34, 0x24, 0x48, 0xBE, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x45, 0x40, 0x66, 0x48, 0x0F, 0x6E, 0xC6, 0x48, 0x8B, 0x34, 0x24, 0x48, 
    0x83, 0xC4, 0x10, 0x48, 0x89, 0xEC, 0x5D, 0xC3, 
];
static DATA: [u8; 0] = [];
static RDATA: [u8; 0] = [];

static SYMBOLS: [Symbol; 1] = [
    Symbol { section: 0, offset: 0, name: [0x6D, 0x61, 0x69, 0x6E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] }
];

static RELOCATIONS: [Relocation; 0] = [];

fn find_runtime_dll() -> Option<std::path::PathBuf> {
    use std::path::PathBuf;
    // 1. 同目录
    let exe_dir = std::env::current_exe().ok()?.parent()?.to_path_buf();
    let local = exe_dir.join("tsn_runtime.dll");
    if local.exists() { return Some(local); }
    // 2. 项目 target/release
    let target_release = exe_dir.join("..").join("..").join("target").join("release").join("tsn_runtime.dll");
    if target_release.exists() { return Some(target_release); }
    // 3. 当前目录
    let current = PathBuf::from("tsn_runtime.dll");
    if current.exists() { return Some(current); }
    None
}

fn main() {
    println!("[{}] Standalone executable: simple", std::env::current_exe().unwrap_or_default().display());

    // 1. 加载 runtime DLL
    let runtime_path = find_runtime_dll()
        .expect("tsn_runtime.dll not found. Please ensure it is in the same directory.");
    println!("[Runtime] Loading: {}", runtime_path.display());

    let wide_path: Vec<u16> = runtime_path
        .as_os_str()
        .encode_wide()
        .chain(Some(0))
        .collect();
    let hmod = unsafe { LoadLibraryW(wide_path.as_ptr()) };
    if hmod.is_null() {
        eprintln!("[ERROR] Failed to load runtime DLL");
        std::process::exit(1);
    }

    // 2. 分配可执行内存
    let code_size = CODE.len();
    if code_size == 0 {
        eprintln!("[ERROR] Code section is empty");
        std::process::exit(1);
    }

    let exec_mem = unsafe {
        VirtualAlloc(ptr::null_mut(), code_size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)
    };
    if exec_mem.is_null() {
        eprintln!("[ERROR] VirtualAlloc failed for code");
        std::process::exit(1);
    }

    unsafe {
        ptr::copy_nonoverlapping(CODE.as_ptr(), exec_mem as *mut u8, code_size);
    }

    // 3. 分配数据内存
    let total_data_size = DATA.len() + RDATA.len();
    let data_mem = if total_data_size > 0 {
        let mem = unsafe {
            VirtualAlloc(ptr::null_mut(), total_data_size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE)
        };
        if mem.is_null() {
            unsafe { VirtualFree(exec_mem, 0, MEM_RELEASE); }
            eprintln!("[ERROR] VirtualAlloc failed for data");
            std::process::exit(1);
        }
        if !DATA.is_empty() {
            unsafe { ptr::copy_nonoverlapping(DATA.as_ptr(), mem as *mut u8, DATA.len()); }
        }
        if !RDATA.is_empty() {
            unsafe {
                ptr::copy_nonoverlapping(
                    RDATA.as_ptr(),
                    (mem as *mut u8).add(DATA.len()),
                    RDATA.len()
                );
            }
        }
        mem
    } else {
        ptr::null_mut()
    };

    // 4. 应用重定位
    let mut reloc_ok = 0usize;
    let mut reloc_fail = 0usize;

    for reloc in RELOCATIONS.iter() {
        let target_name = std::str::from_utf8(&reloc.target_name)
            .unwrap_or("")
            .trim_end_matches('\0');

        if target_name.is_empty() {
            reloc_fail += 1;
            continue;
        }

        let target_addr = if target_name.starts_with("js_") || target_name.starts_with("__") {
            // 从 runtime DLL 解析外部符号
            let c_name = match CString::new(target_name) {
                Ok(s) => s,
                Err(_) => { reloc_fail += 1; continue; }
            };
            let addr = unsafe { GetProcAddress(hmod, c_name.as_ptr() as *const i8) };
            if addr.is_null() {
                eprintln!("[WARN] Unresolved symbol: {}", target_name);
                reloc_fail += 1;
                continue;
            }
            addr
        } else {
            // 内部符号
            let mut found = None;
            for sym in SYMBOLS.iter() {
                let sym_name = std::str::from_utf8(&sym.name)
                    .unwrap_or("")
                    .trim_end_matches('\0');
                if sym_name == target_name {
                    found = Some((sym.section, sym.offset));
                    break;
                }
            }
            match found {
                Some((0, offset)) => (exec_mem as usize + offset as usize) as *mut c_void,
                Some((1, offset)) => {
                    if data_mem.is_null() { reloc_fail += 1; continue; }
                    (data_mem as usize + offset as usize) as *mut c_void
                }
                Some((2, offset)) => {
                    if data_mem.is_null() { reloc_fail += 1; continue; }
                    (data_mem as usize + DATA.len() + offset as usize) as *mut c_void
                }
                _ => { reloc_fail += 1; continue; }
            }
        };

        let patch_addr = (exec_mem as usize + reloc.offset as usize) as *mut u8;
        match reloc.type_ {
            0 => { // REL32
                let rel = (target_addr as isize) - (patch_addr as isize + 4);
                unsafe { *(patch_addr as *mut i32) = rel as i32; }
            }
            1 => { // ADDR64
                unsafe { *(patch_addr as *mut u64) = target_addr as u64; }
            }
            _ => { reloc_fail += 1; continue; }
        }
        reloc_ok += 1;
    }

    println!("[Reloc] {}/{} ok, {} failed", reloc_ok, RELOCATIONS.len(), reloc_fail);

    // 5. 查找入口点并执行
    let mut entry_offset = 0u32;
    for sym in SYMBOLS.iter() {
        let sym_name = std::str::from_utf8(&sym.name)
            .unwrap_or("")
            .trim_end_matches('\0');
        if sym_name == "main" && sym.section == 0 {
            entry_offset = sym.offset;
            break;
        }
    }

    println!("[Exec] Calling entry point (main @ offset {})...", entry_offset);
    let result = unsafe {
        let entry_addr = (exec_mem as usize + entry_offset as usize) as *const u8;
        let fn_ptr: extern "C" fn() -> f64 = std::mem::transmute(entry_addr);
        fn_ptr()
    };

    println!("\n=== Result: {} ===", result);

    // 6. 清理
    unsafe { VirtualFree(exec_mem, 0, MEM_RELEASE); }
    if !data_mem.is_null() {
        unsafe { VirtualFree(data_mem, 0, MEM_RELEASE); }
    }
    unsafe { FreeLibrary(hmod); }
}
