//! TSN FFI 接口 - 导出 DLL 函数供 loader 调用

use std::ffi::{c_char, c_void, CStr, CString};
use std::ptr;

use crate::codegen::CodeGen;
use crate::swc_transform;

// === C 结构体定义（与 tsn_abi.h 对应） ===

#[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],
}

#[repr(C)]
pub struct TsnCompileResult {
    pub code_ptr: *mut u8,
    pub code_len: u32,
    pub data_ptr: *mut u8,
    pub data_len: u32,
    pub rdata_ptr: *mut u8,
    pub rdata_len: u32,
    pub symbols: *mut TsnSymbol,
    pub symbol_count: u32,
    pub relocations: *mut TsnRelocation,
    pub reloc_count: u32,
    pub error_msg: *mut c_char,
    pub error_line: u32,
    pub error_col: u32,
    pub error_context: *mut c_char,
    pub _context: *mut c_void,
    /// addon DLL 名称列表（逗号分隔的 C 字符串）
    pub addon_dlls: *mut c_char,
}

// === 内部上下文结构（用于内存管理） ===

#[allow(dead_code)]
struct CompileContext {
    code: Vec<u8>,
    data: Vec<u8>,
    rdata: Vec<u8>,
    symbols: Vec<TsnSymbol>,
    relocations: Vec<TsnRelocation>,
    error_msg: Option<CString>,
    error_context: Option<CString>,
    addon_dlls: Option<CString>,
}

// === DLL 导出函数 ===

/// 编译 TypeScript 源代码为 TSN 模块
#[no_mangle]
pub extern "C" fn tsn_compile(source: *const c_char) -> *mut TsnCompileResult {
    // 初始化日志（仅首次有效）
    let _ = env_logger::Builder::from_env("TSN_LOG").try_init();
    
    if source.is_null() {
        return create_error_result("Null source pointer");
    }

    let source_str = unsafe {
        match CStr::from_ptr(source).to_str() {
            Ok(s) => s,
            Err(_) => return create_error_result("Invalid UTF-8 source"),
        }
    };

    match compile_internal(source_str) {
        Ok(result) => Box::into_raw(Box::new(result)),
        Err(e) => create_error_result(&e),
    }
}

/// 释放编译结果
#[no_mangle]
pub extern "C" fn tsn_free_result(result: *mut TsnCompileResult) {
    if result.is_null() {
        return;
    }

    unsafe {
        let result = Box::from_raw(result);

        // 释放错误信息
        if !result.error_msg.is_null() {
            let _ = CString::from_raw(result.error_msg);
        }
        if !result.error_context.is_null() {
            let _ = CString::from_raw(result.error_context);
        }
        // 释放 addon DLLs 字符串
        if !result.addon_dlls.is_null() {
            let _ = CString::from_raw(result.addon_dlls);
        }

        // 释放上下文（这会释放所有关联的内存）
        if !result._context.is_null() {
            let _ = Box::from_raw(result._context as *mut CompileContext);
        }
    }
}

/// 获取版本信息
#[no_mangle]
pub extern "C" fn tsn_version() -> *const c_char {
    static VERSION: &str = "ts-native v0.3.2\0";
    VERSION.as_ptr() as *const c_char
}

// === COFF 可选导出（需启用 coff feature）===

#[cfg(feature = "coff")]
mod coff_export {
    use super::*;

    /// 编译 TypeScript 源代码为标准 COFF .obj 字节流
    /// @param source - TypeScript 源代码字符串
    /// @param out_len - 输出 COFF 数据长度（写入）
    /// @return 指向 COFF 字节流的指针，需要用 tsn_free_coff 释放
    #[no_mangle]
pub extern "C" fn tsn_compile_coff(source: *const c_char, out_len: *mut u32) -> *mut u8 {
        let _ = env_logger::Builder::from_env("TSN_LOG").try_init();
        
        if source.is_null() || out_len.is_null() {
            return ptr::null_mut();
        }

        let source_str = unsafe {
            match CStr::from_ptr(source).to_str() {
                Ok(s) => s,
                Err(_) => return ptr::null_mut(),
            }
        };

        match compile_coff_internal(source_str) {
            Ok(bytes) => {
                let len = bytes.len() as u32;
                let ptr = bytes.as_ptr() as *mut u8;
                std::mem::forget(bytes); // 防止释放，由调用者通过 tsn_free_coff 释放
                unsafe { *out_len = len; }
                ptr
            }
            Err(_) => ptr::null_mut(),
        }
    }

    /// 释放 COFF 字节流
    #[no_mangle]
    pub extern "C" fn tsn_free_coff(ptr: *mut u8, len: u32) {
        if !ptr.is_null() && len > 0 {
            unsafe {
                let _ = Vec::from_raw_parts(ptr, len as usize, len as usize);
            }
        }
    }

    fn compile_coff_internal(source: &str) -> Result<Vec<u8>, String> {
        let mut hir = swc_transform::parse(source)
            .map_err(|e| format!("Parse error: {}", e))?;
        let mut codegen = CodeGen::new();
        let coff_bytes = codegen.compile_coff(&mut hir)
            .map_err(|e| format!("Compile error: {}", e))?;
        Ok(coff_bytes)
    }
}

fn compile_internal(source: &str) -> Result<TsnCompileResult, String> {
    use std::time::Instant;
    let total_start = Instant::now();
    
    // 1. 解析 TypeScript
    let parse_start = Instant::now();
    let mut hir = swc_transform::parse(source)
        .map_err(|e| format!("Parse error: {}", e))?;
    let parse_ms = parse_start.elapsed().as_millis() as u64;
    
    // 2. 生成 native 代码（直接获取 raw_data，跳过 TSN 序列化）
    let codegen_start = Instant::now();
    let mut codegen = CodeGen::new();
    let raw_data = codegen.compile_to_raw_data(&mut hir)
        .map_err(|e| format!("Compile error: {}", e))?;
    let codegen_ms = codegen_start.elapsed().as_millis() as u64;
    
    let total_ms = total_start.elapsed().as_millis() as u64;
    
    // 输出编译性能统计
    log::info!(target: "Compiler",
        "Perf: parse={}ms codegen={}ms total={}ms ({} funcs, {} strings)",
        parse_ms, codegen_ms, total_ms,
        codegen.stats().function_count, codegen.stats().string_count);
    
    // 输出 source map 摘要
    let sm = codegen.source_map();
    if !sm.is_empty() {
        log::debug!(target: "Compiler",
            "SourceMap: {} entries (func={}, lines={})",
            sm.len(),
            sm.iter().map(|e| e.func_name.as_str()).collect::<std::collections::HashSet<_>>().len(),
            sm.iter().map(|e| e.src_line).collect::<std::collections::HashSet<_>>().len());
    }

    // 3. 构建代码节区（直接使用 section 数据）
    let mut code = Vec::new();
    for (_, func_data) in &raw_data.functions {
        code.extend_from_slice(func_data);
    }
    // 如果 functions 为空，尝试从 data_items 中找 .text section
    if code.is_empty() {
        for (key, item_data) in &raw_data.data_items {
            if key.starts_with("__text_") {
                code.extend_from_slice(item_data);
            }
        }
    }

    // 4. 构建数据节区（直接使用 section 数据）
    let data = Vec::new();
    let mut rdata = Vec::new();
    for (key, item_data) in &raw_data.data_items {
        if key.starts_with("__text_") {
            continue; // 跳过 .text section
        }
        // 判断是 .data 还是 .rdata
        // 简化处理：所有非 .text 的数据都放入 rdata
        rdata.extend_from_slice(item_data);
    }

    // 5. 转换符号表（直接使用原始偏移）
    let symbols: Vec<TsnSymbol> = raw_data.symbols.iter().map(|s| {
        let mut name = [0u8; 64];
        let bytes = s.name.as_bytes();
        let len = bytes.len().min(63);
        name[..len].copy_from_slice(&bytes[..len]);

        TsnSymbol {
            section: s.section,
            offset: s.offset,
            name,
        }
    }).collect();

    let relocations: Vec<TsnRelocation> = raw_data.relocations.iter().map(|r| {
        let mut target_name = [0u8; 64];
        let bytes = r.target_symbol.as_bytes();
        let len = bytes.len().min(63);
        target_name[..len].copy_from_slice(&bytes[..len]);
        TsnRelocation {
            section: r.section,
            offset: r.offset,
            type_: r.reloc_type,
            _padding: 0,
            target_name,
        }
    }).collect();

    // 8. 创建上下文（拥有所有内存）
    let addon_dlls_cstring = CString::new("").unwrap_or_else(|_| CString::new("").unwrap());
    let addon_dlls_ptr = addon_dlls_cstring.into_raw();

    let mut context = Box::new(CompileContext {
        code,
        data,
        rdata,
        symbols,
        relocations,
        error_msg: None,
        error_context: None,
        addon_dlls: None,
    });

    // 9. 构建结果（指针指向上下文拥有的内存）
    let result = TsnCompileResult {
        code_ptr: context.code.as_mut_ptr(),
        code_len: context.code.len() as u32,
        data_ptr: context.data.as_mut_ptr(),
        data_len: context.data.len() as u32,
        rdata_ptr: context.rdata.as_mut_ptr(),
        rdata_len: context.rdata.len() as u32,
        symbols: context.symbols.as_mut_ptr(),
        symbol_count: context.symbols.len() as u32,
        relocations: context.relocations.as_mut_ptr(),
        reloc_count: context.relocations.len() as u32,
        error_msg: ptr::null_mut(),
        error_line: 0,
        error_col: 0,
        error_context: ptr::null_mut(),
        _context: Box::into_raw(context) as *mut c_void,
        addon_dlls: addon_dlls_ptr,
    };

    Ok(result)
}

fn create_error_result(msg: &str) -> *mut TsnCompileResult {
    let error_cstring = CString::new(msg).unwrap_or_else(|_| CString::new("Unknown error").unwrap());
    let error_ptr = error_cstring.into_raw();

    // 尝试从错误消息中提取行号 (格式: "line N" 或 ":N:")
    let error_line = extract_line_from_error(msg);

    // 提取错误上下文（错误消息的最后 60 字符）
    let context_str = if msg.len() > 60 { &msg[msg.len()-60..] } else { msg };
    let context_cstring = CString::new(context_str).unwrap_or_else(|_| CString::new("").unwrap());
    let context_ptr = context_cstring.into_raw();

    let result = TsnCompileResult {
        code_ptr: ptr::null_mut(),
        code_len: 0,
        data_ptr: ptr::null_mut(),
        data_len: 0,
        rdata_ptr: ptr::null_mut(),
        rdata_len: 0,
        symbols: ptr::null_mut(),
        symbol_count: 0,
        relocations: ptr::null_mut(),
        reloc_count: 0,
        error_msg: error_ptr,
        error_line,
        error_col: 0,
        error_context: context_ptr,
        _context: ptr::null_mut(),
        addon_dlls: ptr::null_mut(),
    };

    Box::into_raw(Box::new(result))
}

/// 从错误消息中提取行号
fn extract_line_from_error(msg: &str) -> u32 {
    // SWC 格式: "at line N" 或 ":N:M" 或 "line N"
    for pattern in ["line ", ":"] {
        if let Some(pos) = msg.find(pattern) {
            let rest = &msg[pos + pattern.len()..];
            let num_str: String = rest.chars().take_while(|c| c.is_ascii_digit()).collect();
            if let Ok(n) = num_str.parse::<u32>() {
                if n > 0 { return n; }
            }
        }
    }
    0
}
