//! 独立可执行文件生成器
//!
//! 为每个编译入口生成一个独立的 .exe 文件，内嵌编译后的机器码和执行引擎。
//! 运行时只需加载 tsn_runtime.dll 解析外部 js_* 符号。

use std::collections::HashMap;
use std::path::Path;
use std::process::Command;
use anyhow::{Result, bail};

/// 编译结果数据（与 loader 中的 CompiledModule 对应）
#[derive(Debug, Clone)]
pub struct ModuleData {
    pub code: Vec<u8>,
    pub data: Vec<u8>,
    pub rdata: Vec<u8>,
    pub symbols: Vec<ModuleSymbol>,
    pub relocations: Vec<ModuleRelocation>,
    /// 需要加载的 addon DLL 名称列表
    pub addon_dlls: Vec<String>,
}

#[derive(Debug, Clone)]
pub struct ModuleSymbol {
    pub section: u8,
    pub offset: u32,
    pub name: String,
}

#[derive(Debug, Clone)]
pub struct ModuleRelocation {
    pub section: u8,
    pub offset: u32,
    pub type_: u8,
    pub target_name: String,
}

/// 生成独立可执行文件的 Rust 源码
pub fn generate_standalone_source(
    module: &ModuleData,
    entry_name: &str,
) -> String {
    let code_bytes = bytes_to_rust_array(&module.code);
    let data_bytes = bytes_to_rust_array(&module.data);
    let rdata_bytes = bytes_to_rust_array(&module.rdata);
    let symbols_code = symbols_to_rust(&module.symbols);
    let relocations_code = relocations_to_rust(&module.relocations);

    // 生成 addon DLL 列表常量
    let addon_dlls_str = format!("{:?}", module.addon_dlls);

    format!(r#"// Auto-generated standalone executable for: {entry_name}
// 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; {}] = {};
static DATA: [u8; {}] = {};
static RDATA: [u8; {}] = {};

{}

{}

/// 需要加载的 addon DLL 名称列表（编译时嵌入）
static ADDON_DLLS: &[&str] = &{addon_dlls_str};

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: {entry_name}", 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);
    }}

    // 1.5 加载 native addon DLLs
    let mut addon_handles: Vec<*mut c_void> = Vec::new();
    for dll_name in ADDON_DLLS {{
        // 搜索顺序：exe 同目录 → 当前工作目录
        let exe_dir = std::env::current_exe().ok().and_then(|p| p.parent()).map(|p| p.to_path_buf());
        let mut loaded = false;

        // 优先从 exe 同目录加载
        if let Some(ref exe_dir) = exe_dir {{
            let dll_path = exe_dir.join(dll_name);
            if dll_path.exists() {{
                let wide_name: Vec<u16> = dll_path.as_os_str().encode_wide().chain(std::iter::once(0)).collect();
                let h = unsafe {{ LoadLibraryW(wide_name.as_ptr()) }};
                if !h.is_null() {{
                    addon_handles.push(h);
                    println!("[Addon] Loaded: {{}}", dll_path.display());
                    loaded = true;
                }}
            }}
        }}

        // 回退到当前工作目录
        if !loaded {{
            let wide_name: Vec<u16> = dll_name.encode_utf16().chain(std::iter::once(0)).collect();
            let h = unsafe {{ LoadLibraryW(wide_name.as_ptr()) }};
            if h.is_null() {{
                eprintln!("[ts-native] 警告: 无法加载 addon DLL: {{}}", dll_name);
            }} else {{
                addon_handles.push(h);
                println!("[Addon] Loaded: {{}}", dll_name);
            }}
        }}
    }}

    // 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 if target_name.starts_with("addon_") {{
            // 从 addon DLLs 解析外部符号
            let c_name = match CString::new(target_name) {{
                Ok(s) => s,
                Err(_) => {{ reloc_fail += 1; continue; }}
            }};
            let mut found = std::ptr::null_mut();
            for &addon_hmod in &addon_handles {{
                found = unsafe {{ GetProcAddress(addon_hmod, c_name.as_ptr() as *const i8) }};
                if !found.is_null() {{ break; }}
            }}
            if found.is_null() {{
                eprintln!("[ts-native] 错误: 无法解析 addon 符号: {{}}", target_name);
                reloc_fail += 1;
                continue;
            }}
            found
        }} 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); }}
    }}
    // 释放 addon DLLs
    for addon_hmod in addon_handles {{
        unsafe {{ FreeLibrary(addon_hmod); }}
    }}
    unsafe {{ FreeLibrary(hmod); }}
}}
"#,
        module.code.len(), code_bytes,
        module.data.len(), data_bytes,
        module.rdata.len(), rdata_bytes,
        symbols_code,
        relocations_code,
    )
}

/// 将字节数组转换为 Rust 静态数组语法
fn bytes_to_rust_array(bytes: &[u8]) -> String {
    if bytes.is_empty() {
        return "[]".to_string();
    }
    let mut result = String::from("[\n    ");
    for (i, b) in bytes.iter().enumerate() {
        result.push_str(&format!("0x{:02X}, ", b));
        if (i + 1) % 16 == 0 {
            result.push_str("\n    ");
        }
    }
    result.push_str("\n]");
    result
}

/// 将符号表转换为 Rust 静态数组
fn symbols_to_rust(symbols: &[ModuleSymbol]) -> String {
    if symbols.is_empty() {
        return "static SYMBOLS: [Symbol; 0] = [];".to_string();
    }

    let mut items = Vec::new();
    for sym in symbols {
        let mut name_bytes = [0u8; 64];
        let name_data = sym.name.as_bytes();
        let len = name_data.len().min(63);
        name_bytes[..len].copy_from_slice(&name_data[..len]);

        let bytes_str: Vec<String> = name_bytes.iter()
            .map(|b| format!("0x{:02X}", b))
            .collect();

        items.push(format!(
            "Symbol {{ section: {}, offset: {}, name: [{}] }}",
            sym.section,
            sym.offset,
            bytes_str.join(", ")
        ));
    }

    format!(
        "static SYMBOLS: [Symbol; {}] = [\n    {}\n];",
        symbols.len(),
        items.join(",\n    ")
    )
}

/// 将重定位表转换为 Rust 静态数组
fn relocations_to_rust(relocations: &[ModuleRelocation]) -> String {
    if relocations.is_empty() {
        return "static RELOCATIONS: [Relocation; 0] = [];".to_string();
    }

    let mut items = Vec::new();
    for reloc in relocations {
        let mut name_bytes = [0u8; 64];
        let name_data = reloc.target_name.as_bytes();
        let len = name_data.len().min(63);
        name_bytes[..len].copy_from_slice(&name_data[..len]);

        let bytes_str: Vec<String> = name_bytes.iter()
            .map(|b| format!("0x{:02X}", b))
            .collect();

        items.push(format!(
            "Relocation {{ section: {}, offset: {}, type_: {}, _padding: 0, target_name: [{}] }}",
            reloc.section,
            reloc.offset,
            reloc.type_,
            bytes_str.join(", ")
        ));
    }

    format!(
        "static RELOCATIONS: [Relocation; {}] = [\n    {}\n];",
        relocations.len(),
        items.join(",\n    ")
    )
}

/// 编译生成的 Rust 源码为可执行文件
pub fn compile_rust_to_exe(
    source_path: &Path,
    output_path: &Path,
) -> Result<()> {
    // 确保输出目录存在
    if let Some(parent) = output_path.parent() {
        std::fs::create_dir_all(parent)?;
    }

    let output = Command::new("rustc")
        .args(&[
            "--edition", "2021",
            "-C", "opt-level=2",
            "-o", output_path.to_str().unwrap(),
            source_path.to_str().unwrap(),
        ])
        .output()
        .map_err(|e| anyhow::anyhow!("Failed to run rustc: {}", e))?;

    if !output.status.success() {
        let stderr = String::from_utf8_lossy(&output.stderr);
        bail!("rustc compilation failed:\n{}", stderr);
    }

    Ok(())
}

/// 从 COFF .obj 文件解析为 ModuleData
pub fn parse_coff_to_module_data(obj_bytes: &[u8]) -> Result<ModuleData> {
    use object::{Object, ObjectSection, ObjectSymbol, RelocationTarget, SectionKind};

    let obj = object::File::parse(obj_bytes)
        .map_err(|e| anyhow::anyhow!("Failed to parse COFF: {}", e))?;

    let mut section_map: HashMap<u8, u8> = HashMap::new();
    let mut code = Vec::new();
    let mut data = Vec::new();
    let mut rdata = Vec::new();

    for (idx, section) in obj.sections().enumerate() {
        let coff_idx = idx as u8;
        let kind = section.kind();
        let sec_data = section.data().unwrap_or(&[]).to_vec();

        if kind == SectionKind::Text {
            section_map.insert(coff_idx, 0);
            code = sec_data;
        } else if kind == SectionKind::Data {
            section_map.insert(coff_idx, 1);
            data = sec_data;
        } else if kind == SectionKind::ReadOnlyData {
            section_map.insert(coff_idx, 2);
            rdata = sec_data;
        }
    }

    let symbol_vec: Vec<_> = obj.symbols().collect();

    let mut symbols = Vec::new();
    for (_idx, sym) in obj.symbols().enumerate() {
        let name = sym.name().unwrap_or("").to_string();
        if name.is_empty() { continue; }

        let section_idx = match sym.section() {
            object::SymbolSection::Section(sec_idx) => {
                let coff_idx = (sec_idx.0 as u8).saturating_sub(1);
                *section_map.get(&coff_idx).unwrap_or(&0xFF)
            }
            object::SymbolSection::Undefined => 0xFF,
            object::SymbolSection::Absolute => 0xFE,
            _ => continue,
        };
        let offset = sym.address() as u32;
        symbols.push(ModuleSymbol {
            section: section_idx,
            offset,
            name,
        });
    }

    let mut relocations = Vec::new();
    for (idx, section) in obj.sections().enumerate() {
        let coff_idx = idx as u8;
        let internal_idx = *section_map.get(&coff_idx).unwrap_or(&0xFF);
        if internal_idx == 0xFF { continue; }

        for (offset, reloc) in section.relocations() {
            let raw_sym_idx = match reloc.target() {
                RelocationTarget::Symbol(sym_idx) => sym_idx.0,
                _ => continue,
            };

            let target_name = parse_coff_symbol_name(obj_bytes, raw_sym_idx)
                .or_else(|| {
                    symbol_vec.get(raw_sym_idx)
                        .and_then(|s| s.name().ok())
                        .map(|s| s.to_string())
                })
                .unwrap_or_default();

            if target_name.is_empty() { continue; }

            let type_ = match reloc.kind() {
                object::RelocationKind::Relative => 0u8,
                object::RelocationKind::Absolute => 1u8,
                _ => continue,
            };

            relocations.push(ModuleRelocation {
                section: internal_idx,
                offset: offset as u32,
                type_,
                target_name,
            });
        }
    }

    Ok(ModuleData {
        code,
        data,
        rdata,
        symbols,
        relocations,
        addon_dlls: Vec::new(),
    })
}

/// 将 ModuleData 序列化为 .tsnobj 二进制文件
///
/// 格式：
/// [Header: ModuleDataHeader]
/// [code: u8 x code_len]
/// [data: u8 x data_len]
/// [rdata: u8 x rdata_len]
/// [symbols: Symbol x symbol_count]
/// [relocations: Relocation x reloc_count]
#[repr(C)]
pub struct ModuleDataHeader {
    pub code_len: u32,
    pub data_len: u32,
    pub rdata_len: u32,
    pub symbol_count: u32,
    pub reloc_count: u32,
    pub entry_name: [u8; 64],
}

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

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

pub fn serialize_to_tsnobj(module: &ModuleData, entry_name: &str) -> Vec<u8> {
    let mut result = Vec::new();

    // Header
    let mut name_bytes = [0u8; 64];
    let name_data = entry_name.as_bytes();
    let len = name_data.len().min(63);
    name_bytes[..len].copy_from_slice(&name_data[..len]);

    let header = ModuleDataHeader {
        code_len: module.code.len() as u32,
        data_len: module.data.len() as u32,
        rdata_len: module.rdata.len() as u32,
        symbol_count: module.symbols.len() as u32,
        reloc_count: module.relocations.len() as u32,
        entry_name: name_bytes,
    };

    // 写入 header
    let header_bytes = unsafe {
        std::slice::from_raw_parts(
            &header as *const _ as *const u8,
            std::mem::size_of::<ModuleDataHeader>()
        )
    };
    result.extend_from_slice(header_bytes);

    // 写入 code
    result.extend_from_slice(&module.code);

    // 写入 data
    result.extend_from_slice(&module.data);

    // 写入 rdata
    result.extend_from_slice(&module.rdata);

    // 写入 symbols
    for sym in &module.symbols {
        let mut name_bytes = [0u8; 64];
        let name_data = sym.name.as_bytes();
        let len = name_data.len().min(63);
        name_bytes[..len].copy_from_slice(&name_data[..len]);

        let tsn_sym = TsnSymbol {
            section: sym.section,
            offset: sym.offset,
            name: name_bytes,
        };
        let sym_bytes = unsafe {
            std::slice::from_raw_parts(
                &tsn_sym as *const _ as *const u8,
                std::mem::size_of::<TsnSymbol>()
            )
        };
        result.extend_from_slice(sym_bytes);
    }

    // 写入 relocations
    for reloc in &module.relocations {
        let mut name_bytes = [0u8; 64];
        let name_data = reloc.target_name.as_bytes();
        let len = name_data.len().min(63);
        name_bytes[..len].copy_from_slice(&name_data[..len]);

        let tsn_reloc = TsnRelocation {
            section: reloc.section,
            offset: reloc.offset,
            type_: reloc.type_,
            _padding: 0,
            target_name: name_bytes,
        };
        let reloc_bytes = unsafe {
            std::slice::from_raw_parts(
                &tsn_reloc as *const _ as *const u8,
                std::mem::size_of::<TsnRelocation>()
            )
        };
        result.extend_from_slice(reloc_bytes);
    }

    result
}

/// 从原始 COFF 数据解析符号名称
fn parse_coff_symbol_name(data: &[u8], sym_idx: usize) -> Option<String> {
    let _num_sections = u16::from_le_bytes([data[2], data[3]]) as usize;
    let sym_ptr = u32::from_le_bytes([data[8], data[9], data[10], data[11]]) as usize;
    let num_syms = u32::from_le_bytes([data[12], data[13], data[14], data[15]]) as usize;

    if sym_idx >= num_syms {
        return None;
    }

    let sym_off = sym_ptr + sym_idx * 18;
    if sym_off + 18 > data.len() {
        return None;
    }

    let name_bytes = &data[sym_off..sym_off+8];
    if name_bytes[0..4] == [0, 0, 0, 0] {
        let str_offset = u32::from_le_bytes([name_bytes[4], name_bytes[5], name_bytes[6], name_bytes[7]]) as usize;
        let str_tab_start = sym_ptr + num_syms * 18;
        let actual_str_off = str_tab_start + str_offset;
        if actual_str_off >= data.len() {
            return None;
        }
        let end = data[actual_str_off..].iter().position(|&b| b == 0).unwrap_or(data.len() - actual_str_off);
        Some(String::from_utf8_lossy(&data[actual_str_off..actual_str_off+end]).to_string())
    } else {
        let end = name_bytes.iter().position(|&b| b == 0).unwrap_or(8);
        Some(String::from_utf8_lossy(&name_bytes[..end]).to_string())
    }
}
