//! Native Linker 独立可执行文件
//!
//! 用法：
//!   native-linker input.o -o output.exe
//!   native-linker input1.o input2.o -o output.exe

use anyhow::Result;
use std::path::Path;

// 链接 Windows 系统库
#[link(name = "shell32")]
extern "C" {}

// 引用 src 目录下的模块
#[path = "../native_linker.rs"]
mod native_linker;

#[path = "../kernel32_functions.rs"]
mod kernel32_functions;

#[path = "../coff.rs"]
mod coff;

fn main() -> Result<()> {
    let args: Vec<String> = std::env::args().collect();
    
    if args.len() < 3 {
        eprintln!("Usage: native-linker <input.o...> -o <output.exe>");
        eprintln!();
        eprintln!("Examples:");
        eprintln!("  native-linker main.o -o main.exe");
        eprintln!("  native-linker main.o runtime.o -o app.exe");
        std::process::exit(1);
    }
    
    // 解析参数
    let mut input_files = Vec::new();
    let mut output_file = String::new();
    
    let mut i = 1;
    while i < args.len() {
        match args[i].as_str() {
            "-o" | "--output" => {
                i += 1;
                if i < args.len() {
                    output_file = args[i].clone();
                }
            }
            arg if !arg.starts_with('-') => {
                input_files.push(arg.to_string());
            }
            _ => {}
        }
        i += 1;
    }
    
    if input_files.is_empty() {
        eprintln!("Error: no input files specified");
        std::process::exit(1);
    }
    
    if output_file.is_empty() {
        // 默认输出文件名
        if let Some(first_input) = input_files.first() {
            let path = Path::new(first_input);
            if let Some(stem) = path.file_stem() {
                output_file = format!("{}.exe", stem.to_string_lossy());
            } else {
                output_file = "a.exe".to_string();
            }
        } else {
            output_file = "a.exe".to_string();
        }
    }
    
    println!("🔗 Native Linker");
    println!("  输入: {} 个对象文件", input_files.len());
    println!("  输出: {}", output_file);
    println!();
    
    // 执行链接
    link_files(&input_files, &output_file)?;
    
    println!("✅ 链接成功: {}", output_file);
    
    Ok(())
}

fn link_files(input_files: &[String], output_file: &str) -> Result<()> {
    use native_linker::*;
    
    // 创建链接器配置
    let mut native = NativeLinker::new(NativeLinkConfig {
        entry_point: "_start".to_string(),
        subsystem: Subsystem::Console,
        image_base: 0x140000000,
        stack_reserve: 0x100000,
        stack_commit: 0x1000,
        heap_reserve: 0x100000,
        heap_commit: 0x1000,
        imports: vec![
            DllImport {
                dll_name: "kernel32.dll".to_string(),
                functions: vec![
                    // runtime_nocrt.c 使用的函数
                    "ExitProcess".to_string(),
                    "GetCommandLineW".to_string(),
                    "GetProcessHeap".to_string(),
                    "GetStdHandle".to_string(),
                    "GetSystemTimeAsFileTime".to_string(),
                    "HeapAlloc".to_string(),
                    "HeapFree".to_string(),
                    "LocalFree".to_string(),
                    "QueryPerformanceCounter".to_string(),
                    "QueryPerformanceFrequency".to_string(),
                    "SetConsoleOutputCP".to_string(),
                    "Sleep".to_string(),
                    "WideCharToMultiByte".to_string(),
                    "WriteFile".to_string(),
                ],
            },
            DllImport {
                dll_name: "ntdll.dll".to_string(),
                functions: vec![
                    // runtime_nocrt.c 使用的函数
                    "RtlMoveMemory".to_string(),
                ],
            },
            DllImport {
                dll_name: "shell32.dll".to_string(),
                functions: vec![
                    "CommandLineToArgvW".to_string(),
                ],
            },
        ],
        auto_inject_runtime: true,
        runtime_objects: vec![
            "start_nocrt.o".to_string(),
            "runtime_nocrt.o".to_string(),
        ],
    });
    
    // 加载所有输入文件（支持 TSN 和 COFF 混合格式）
    for input_file in input_files.iter() {
        native.add_input(input_file)
            .map_err(|e| anyhow::anyhow!("加载 {} 失败: {}", input_file, e))?;
    }
    
    println!("  📦 已加载 {} 个输入文件", input_files.len());
    
    // 执行链接
    let pe_data = native.link()
        .map_err(|e| anyhow::anyhow!("链接失败: {}", e))?;
    
    // 写入输出文件
    std::fs::write(output_file, &pe_data)
        .map_err(|e| anyhow::anyhow!("写入 {} 失败: {}", output_file, e))?;
    
    println!("  📊 PE 文件大小: {} bytes", pe_data.len());
    
    Ok(())
}
