// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
//  generator.rs — IR → Rust 代码
//
//  公开接口:
//    generate_api_file(kind, methods, config) → String
//    generate_spi_file(kind, methods, config) → String
//
//  内部按 API / SPI / 辅助函数 三个区域组织。
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

use super::parser::*;

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
//  API 代码生成
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

/// 生成完整的 API 文件内容（如 traderapi.rs / mdapi.rs）
pub fn generate_api_file(kind: ApiKind, methods: &[MethodInfo], config: &CodegenConfig) -> String {
    let mut code = String::with_capacity(16 * 1024);
    code.push_str(&generate_api_header(kind));
    code.push_str(&generate_api_struct_def(kind));
    code.push_str(&generate_api_impl_block(kind, methods, config));
    code
}

fn generate_api_header(kind: ApiKind) -> String {
    let version = "v1alpha1";
    let spi_mod = kind.spi_mod();
    format!(
        r#"/* generated by codegen */
use std::{{
    ffi::{{CStr, CString}},
    os::raw::c_char,
    path::Path,
    ptr::null_mut,
    sync::atomic::{{AtomicBool, AtomicPtr, Ordering}},
}};

use libloading::Library;

use crate::{version}::bindings::*;
use crate::{version}::{spi_mod}::*;    
"#
    )
}

fn generate_api_struct_def(kind: ApiKind) -> String {
    let api_name = kind.api_name();
    let api_class = kind.api_class();
    let spi_class = kind.spi_class();
    format!(
        r#"
#[derive(Debug)]
pub struct {api_name} {{
    pub api_ptr: *mut {api_class},
    pub spi_ptr: AtomicPtr<{spi_class}Ext>,
    pub dynlib: Option<Library>,          
    pub released: AtomicBool,
}}

unsafe impl Sync for {api_name} {{}}
unsafe impl Send for {api_name} {{}}

"#
    )
}
fn generate_api_impl_block(
    kind: ApiKind,
    methods: &[MethodInfo],
    config: &CodegenConfig,
) -> String {
    let api_name = kind.api_name();
    let mut code = format!("impl {} {{\n", api_name);
    for m in methods.iter().filter(|m| !m.is_static) {
        code.push_str(&generate_api_method(kind, m, config));
    }
    code.push_str("}\n");
    code
}

/// 根据 MethodKind 分发到对应的生成函数
fn generate_api_method(kind: ApiKind, m: &MethodInfo, config: &CodegenConfig) -> String {
    match &m.method_kind {
        MethodKind::RegisterSpi => generate_register_spi(kind, m),
        MethodKind::Release => generate_release(kind, m),
        MethodKind::RegisterString => generate_register_string(kind, m),
        MethodKind::Subscribe => generate_subscribe(kind, m),
        MethodKind::General => generate_general(kind, m, config),
        MethodKind::Static => String::new(),
    }
}

// ─── API: 普通方法 ──────────────────────────────────────────

fn generate_general(kind: ApiKind, m: &MethodInfo, config: &CodegenConfig) -> String {
    let api_class = kind.api_class();
    let cpp_name = &m.cpp_name;
    let rust_name = &m.rust_name;
    let comment = &m.comment;

    // 构建参数列表
    let mut arg_parts: Vec<String> = vec!["&self".to_string()];
    let mut call_parts: Vec<String> = vec!["self.api_ptr".to_string()];

    for p in &m.params {
        arg_parts.push(format!("{}: {}", p.rust_name, param_api_type(p, config)));
        call_parts.push(param_api_call(p, config));
    }

    let args_text = arg_parts.join(", ");
    let params_text = call_parts.join(", ");
    let result_sig = return_type_api_sig(&m.return_type);

    // 处理返回 const char * 的特殊情况
    let body = match m.return_type {
        ReturnType::CharPtr => format!(
            r#"
        unsafe {{
            let cstr_ptr = ((*(*self.api_ptr).vtable_).{api_class}_{cpp_name})({params_text});
            let c_str = CStr::from_ptr(cstr_ptr);
            c_str.to_string_lossy().to_string()
        }}"#
        ),
        _ => format!(
            r#"
        unsafe {{
            ((*(*self.api_ptr).vtable_).{api_class}_{cpp_name})({params_text})
        }}"#
        ),
    };

    format!(
        r#"    {comment}
    pub fn {rust_name}({args_text}){result_sig}{{{body}
    }}
    "#
    )
}

// ─── API: RegisterSpi ───────────────────────────────────────

fn generate_register_spi(kind: ApiKind, m: &MethodInfo) -> String {
    let api_class = kind.api_class();
    let spi_class = kind.spi_class();
    let spi_trait = kind.spi_name();
    let arg_name = &m.params[0].rust_name;

    let safety_doc = format!(
        r#"    /// # Safety
    ///
    /// `{arg_name}` 必须指向一个通过 `Box::into_raw(Box::new(...))` 创建的有效 `dyn {spi_trait}` 对象。
    /// 调用者需确保该 SPI 对象在以下时间段内保持有效（不被释放）：
    /// - 从调用 `register_spi` 开始，直到下一次调用 `register_spi`（届时旧 SPI 会被自动释放）
    /// - 或直到所属的 API 对象被 Drop
    ///
    /// 若 SPI 回调中持有 API 指针以实现双向调用，需确保 API 的生命周期长于 SPI。
    /// 典型用法：通过 `Box::into_raw` 创建裸指针传入，由内部自动管理释放。"#
    );

    format!(
        r#"    {comment}
{safety_doc}
    pub fn register_spi(&self, {arg_name}: *mut dyn {spi_trait}) {{
        let spi_ptr = Box::into_raw(Box::new({spi_class}Ext::new({arg_name})));
        let last_spi_ptr = self.spi_ptr.swap(spi_ptr, Ordering::AcqRel);
        unsafe {{
            ((*(*self.api_ptr).vtable_).{api_class}_RegisterSpi)(self.api_ptr, spi_ptr as _)
        }}
        if !last_spi_ptr.is_null() {{
            unsafe {{
                let _ = Box::from_raw(last_spi_ptr); // 释放动态分配的内存
            }}
        }}
    }}
    "#,
        comment = m.comment,
    )
}

// ─── API: Release ───────────────────────────────────────────

fn generate_release(kind: ApiKind, m: &MethodInfo) -> String {
    let api_class = kind.api_class();
    let comment = &m.comment;

    format!(
        r#"    {comment}
    pub fn release(&self) {{
        // 只调用一次底层 Release
        if !self.released.swap(true, Ordering::SeqCst) {{
            unsafe {{
                if !self.api_ptr.is_null() {{
                    ((*(*self.api_ptr).vtable_).{api_class}_Release)(self.api_ptr);
                }}
            }}
        }}
    }}
    "#
    )
}

// ─── API: RegisterFront / RegisterNameServer ────────────────

fn generate_register_string(kind: ApiKind, m: &MethodInfo) -> String {
    let api_class = kind.api_class();
    let cpp_name = &m.cpp_name;
    let rust_name = &m.rust_name;
    let comment = &m.comment;
    let arg_name = &m.params[0].rust_name;

    format!(
        r#"    {comment}
    pub fn {rust_name}(&self, {arg_name}: &str) {{
        unsafe {{
            let {arg_name} = CString::new({arg_name}).unwrap();
            ((*(*self.api_ptr).vtable_).{api_class}_{cpp_name})(self.api_ptr, {arg_name}.as_ptr() as *mut i8)
        }}
    }}
    "#
    )
}

// ─── API: Subscribe/UnSubscribe ─────────────────────────────

fn generate_subscribe(kind: ApiKind, m: &MethodInfo) -> String {
    let api_class = kind.api_class();
    let cpp_name = &m.cpp_name;
    let rust_name = &m.rust_name;
    let comment = &m.comment;
    let arg_name = &m.params[0].rust_name;
    let result_sig = return_type_api_sig(&m.return_type);

    format!(
        r#"    {comment}
    pub fn {rust_name}(&self, {arg_name}: &[impl AsRef<str>]){result_sig}{{
        let cstrings: Vec<_> = {arg_name}.iter().map(|x| CString::new(x.as_ref()).unwrap()).collect();
        let cstr_slice: Vec<*const i8> = cstrings.iter().map(|cstr| cstr.as_ptr()).collect();
        unsafe {{
            ((*(*self.api_ptr).vtable_).{api_class}_{cpp_name})(self.api_ptr, cstr_slice.as_ptr() as *mut *mut i8, {arg_name}.len() as i32)
        }}    
    }}
    "#
    )
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
//  SPI 代码生成
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

/// 生成完整的 SPI 文件内容（如 traderspi.rs / mdspi.rs）
///
/// 输出 4 个部分：
/// 1. trait XxxSpi: Send { ... }
/// 2. #[repr(C)] struct XxxSpiVTable { ... }
/// 3. static SPI_VTABLE + struct CThostFtdcXxxSpiExt
/// 4. extern "C" fn spi_xxx(...) { ... }
pub fn generate_spi_file(kind: ApiKind, methods: &[MethodInfo], config: &CodegenConfig) -> String {
    let mut code = String::with_capacity(16 * 1024);
    code.push_str(&generate_spi_header(kind));
    code.push_str(&generate_spi_trait(kind, methods, config));
    code.push_str(&generate_vtable_struct(kind, methods));
    code.push_str(&generate_static_table_and_ext(kind, methods));
    code.push_str(&generate_extern_fns(kind, methods, config));
    code
}

fn generate_spi_header(_kind: ApiKind) -> String {
    let version = "v1alpha1";
    format!(
        r#"/* generated by codegen */

use crate::{version}::bindings::*;
"#
    )
}

// ─── SPI: trait 定义 ────────────────────────────────────────

fn generate_spi_trait(kind: ApiKind, methods: &[MethodInfo], config: &CodegenConfig) -> String {
    let spi_name = kind.spi_name();
    let mut entries = String::new();

    for m in methods {
        let mut arg_parts: Vec<String> = vec!["&mut self".to_string()];
        for p in &m.params {
            arg_parts.push(format!("{}: {}", p.rust_name, param_trait_type(p, config)));
        }
        let comment = &m.comment;
        let rust_name = &m.rust_name;
        let arg_list = arg_parts.join(", ");
        entries.push_str(&format!(
            r#"   
    {comment}
    fn {rust_name}({arg_list}) {{
    }}"#
        ));
    }

    format!(
        r#"
pub trait {spi_name}: Send {{{entries}
}}"#
    )
}

// ─── SPI: VTable 结构体 ────────────────────────────────────

fn generate_vtable_struct(kind: ApiKind, methods: &[MethodInfo]) -> String {
    let spi_name = kind.spi_name();
    let spi_class = kind.spi_class();
    let mut fields = String::new();

    for m in methods {
        let rust_name = &m.rust_name;
        let mut arg_parts: Vec<String> = vec![format!("spi: *mut {spi_class}Ext")];
        for p in &m.params {
            arg_parts.push(format!("{}: {}", p.rust_name, param_ffi_type(p)));
        }
        fields.push_str(&format!(
            "    {rust_name}: unsafe extern \"C\" fn({}),\n",
            arg_parts.join(", ")
        ));
    }

    format!(
        r#"
#[repr(C)]
#[derive(Debug)]
pub struct {spi_name}VTable {{
{fields}}}"#
    )
}

// ─── SPI: Static table + Ext 结构体 ────────────────────────

fn generate_static_table_and_ext(kind: ApiKind, methods: &[MethodInfo]) -> String {
    let spi_name = kind.spi_name();
    let spi_class = kind.spi_class();

    // static SPI_VTABLE 初始化
    let mut members = String::new();
    for m in methods {
        let rust_name = &m.rust_name;
        members.push_str(&format!("    {rust_name}: spi_{rust_name},\n"));
    }

    format!(
        r#"
static SPI_VTABLE: {spi_name}VTable = {spi_name}VTable {{
{members}}};

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct {spi_class}Ext {{
    vtable: *const {spi_name}VTable,
    pub spi_ptr: *mut dyn {spi_name},
}}

impl {spi_class}Ext {{
    pub fn new(spi: *mut dyn {spi_name}) -> Self {{
        Self {{
            vtable: &SPI_VTABLE,
            spi_ptr: spi,
        }}
    }}
}}
"#
    )
}

// ─── SPI: extern "C" 桥接函数 ──────────────────────────────

fn generate_extern_fns(kind: ApiKind, methods: &[MethodInfo], config: &CodegenConfig) -> String {
    let spi_class = kind.spi_class();
    let mut code = String::new();

    for m in methods {
        let rust_name = &m.rust_name;

        // 函数签名参数
        let mut sig_parts: Vec<String> = vec![format!("spi: *mut {spi_class}Ext")];
        for p in &m.params {
            sig_parts.push(format!("{}: {}", p.rust_name, param_ffi_type(p)));
        }

        // trait 调用参数（转换表达式）
        let call_parts: Vec<String> = m
            .params
            .iter()
            .map(|p| param_ffi_to_trait(p, config))
            .collect();
        let call_args = call_parts.join(", ");

        code.push_str(&format!(
            r#"
extern "C" fn spi_{rust_name}({sig}) {{
    unsafe {{
        (*(*spi).spi_ptr).{rust_name}({call_args})
    }}
}}"#,
            sig = sig_parts.join(", "),
        ));
    }

    code
}

// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
//  共享辅助函数
// ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

/// API 端参数的 Rust 类型签名（受 api_pointer_style 控制）
fn param_api_type(p: &ParamInfo, config: &CodegenConfig) -> String {
    match &p.kind {
        ParamKind::Int => "i32".into(),
        ParamKind::Bool => "bool".into(),
        ParamKind::Enum(name) => name.clone(),
        ParamKind::CharPtr => "&str".into(),
        ParamKind::StructPtr(name) => match config.api_pointer_style {
            PointerStyle::RawConst => format!("*const {}", name),
            PointerStyle::RawMut => format!("*mut {}", name),
            PointerStyle::MutRef => format!("&mut {}", name),
            PointerStyle::Ref => format!("&{}", name),
            PointerStyle::OptionRef => format!("Option<&{}>", name),
        },
        ParamKind::IncompleteArray => "&[impl AsRef<str>]".into(),
        ParamKind::ConstantArray(name) => name.clone(),
    }
}

/// API 端参数的 vtable 调用表达式（受 api_pointer_style 控制）
fn param_api_call(p: &ParamInfo, config: &CodegenConfig) -> String {
    let name = &p.rust_name;
    match &p.kind {
        ParamKind::Int | ParamKind::Bool | ParamKind::Enum(_) => name.clone(),
        ParamKind::StructPtr(type_name) => match config.api_pointer_style {
            PointerStyle::RawConst => format!("{name} as *mut {type_name}"),
            PointerStyle::RawMut => name.clone(),
            PointerStyle::MutRef => format!("{name} as *mut {type_name}"),
            PointerStyle::Ref => format!("{name} as *const {type_name} as *mut {type_name}"),
            PointerStyle::OptionRef => format!("{name}.map_or(std::ptr::null_mut(), |p| p as *const {type_name} as *mut {type_name})"),
        },
        ParamKind::CharPtr => format!("CString::new({name}).unwrap().as_ptr() as *mut i8"),
        ParamKind::ConstantArray(_) => format!("{name}.as_ptr() as *mut i8"),
        ParamKind::IncompleteArray => {
            panic!("IncompleteArray 应由 generate_subscribe 处理")
        }
    }
}

/// SPI trait 端参数的 Rust 类型签名（受 spi_pointer_style 控制）
fn param_trait_type(p: &ParamInfo, config: &CodegenConfig) -> String {
    match &p.kind {
        ParamKind::Int => "i32".into(),
        ParamKind::Bool => "bool".into(),
        ParamKind::Enum(name) => name.clone(),
        ParamKind::StructPtr(name) => match config.spi_pointer_style {
            PointerStyle::RawConst => format!("*const {}", name),
            PointerStyle::RawMut => format!("*mut {}", name),
            PointerStyle::MutRef => format!("&mut {}", name),
            PointerStyle::Ref => format!("&{}", name),
            PointerStyle::OptionRef => format!("Option<&{}>", name),
        },
        other => panic!("SPI 方法不应有此参数类型: {:?}", other),
    }
}

/// SPI VTable / extern "C" 端参数的 Rust 类型签名（始终为原始指针）
fn param_ffi_type(p: &ParamInfo) -> String {
    match &p.kind {
        ParamKind::Int => "std::os::raw::c_int".into(),
        ParamKind::Bool => "bool".into(),
        ParamKind::Enum(name) => name.clone(),
        ParamKind::StructPtr(name) => format!("*const {}", name),
        other => panic!("SPI 方法不应有此参数类型: {:?}", other),
    }
}

/// extern "C" fn 中调用 trait 方法时的参数转换表达式（受 spi_pointer_style 控制）
fn param_ffi_to_trait(p: &ParamInfo, config: &CodegenConfig) -> String {
    match &p.kind {
        ParamKind::StructPtr(_) => match config.spi_pointer_style {
            PointerStyle::RawConst => p.rust_name.clone(),
            PointerStyle::RawMut => format!("{} as *mut _", p.rust_name),
            PointerStyle::MutRef => format!("&mut *{}", p.rust_name),
            PointerStyle::Ref => format!("&*{}", p.rust_name),
            PointerStyle::OptionRef => format!("{}.as_ref()", p.rust_name),
        },
        _ => p.rust_name.clone(),
    }
}

/// API 端返回类型签名
fn return_type_api_sig(rt: &ReturnType) -> String {
    match rt {
        ReturnType::Void => " ".into(),
        ReturnType::Int => " -> i32 ".into(),
        ReturnType::CharPtr => " -> String ".into(),
    }
}
