#![allow(unused_variables, unused_mut)]
#![allow(unused_imports, unused_parens)]
use inflector::Inflector;

use clang::{Entity, EntityKind, EntityVisitResult, TypeKind};

use super::setting::*;

pub fn prepare_api_wrapper_code(ctx: &mut Context, e: &Entity) -> String {
    let code_1 = traverse_ast(ctx, e);
    code_1
}

pub fn prepare_spi_wrapper_code(ctx: &mut Context, e: &Entity) -> String {
    ctx.cfg.module_flavor = ModuleFlavor::SpiTrait;
    let code_0 = traverse_ast(ctx, e);

    ctx.cfg = Config {
        module_flavor: ModuleFlavor::VTableStruct,
        prefer_pointer: PointerStyle::RawPointerConst,
        prefer_param_cffi_type: true,
        param_trim_prefix: false,
        ..ctx.cfg.clone()
    };
    ctx.methods
        .insert("_".to_string(), Box::new(convert_spi_vtable_struct_));
    let code_1 = traverse_ast(ctx, e);

    ctx.cfg = Config {
        module_flavor: ModuleFlavor::StaticTable,
        prefer_pointer: PointerStyle::RawPointerConst,
        prefer_param_cffi_type: true,
        param_trim_prefix: false,
        ..ctx.cfg.clone()
    };
    ctx.methods
        .insert("_".to_string(), Box::new(convert_spi_static_vtable_));

    let code_2 = traverse_ast(ctx, e);

    ctx.cfg = Config {
        module_flavor: ModuleFlavor::ExternCFn,
        prefer_pointer: PointerStyle::RawPointerConst,
        prefer_param_cffi_type: true,
        param_trim_prefix: false,
        ..ctx.cfg.clone()
    };
    ctx.methods
        .insert("_".to_string(), Box::new(convert_spi_cfunc_));

    let code_3 = traverse_ast(ctx, e);

    let version = &ctx.cfg.version;
    format!(
        r#"/* generated by handle_module_spi */

use crate::{version}::bindings::*;
{code_0}
{code_1}
{code_2}
{code_3}
"#
    )
}

pub fn traverse_ast(ctx: &mut Context, e: &Entity) -> String {
    let mut lines = vec![];
    e.visit_children(|c, _p| {
        if c.get_kind() == EntityKind::ClassDecl {
            let name = c.get_name().unwrap();
            if name == ctx.cfg.source_class_name {
                let list = c
                    .get_children()
                    .into_iter()
                    .filter(|e| e.get_kind() == EntityKind::Method && !e.is_static_method())
                    .map(|m| m)
                    .collect::<Vec<_>>();

                let func_vec = list
                    .iter()
                    .map(|m| {
                        let params = m
                            .get_arguments()
                            .unwrap()
                            .iter()
                            .map(|a| {
                                let pt = a.get_type().unwrap();
                                convert_param_type(&ctx, a)
                            })
                            .collect::<Vec<_>>();
                        let func_name = m.get_name().unwrap();
                        if let Some(func_handler) = ctx.methods.get(&func_name) {
                            func_handler(ctx, m, &params)
                        } else {
                            ctx.methods.get("_").unwrap()(ctx, m, &params)
                        }
                    })
                    .collect::<Vec<_>>();
                // call module handler here
                let module_handler = ctx.modules.get(&ctx.cfg.module_flavor).unwrap();
                lines.push(module_handler(ctx, &c, &func_vec))
            }
            EntityVisitResult::Continue
        } else {
            if c.get_kind() == EntityKind::ParmDecl {
                println!("{:?}", c);
            }
            if cfg!(feature = "sopt") {
                EntityVisitResult::Recurse
            } else {
                EntityVisitResult::Continue
            }
        }
    });
    lines.join("")
}

pub fn handle_module_api_trait(ctx: &Context, e: &Entity, items: &ItemVec) -> String {
    let version = &ctx.cfg.version;
    let trait_name = &ctx.cfg.generate_trait_name;
    let api_class = &ctx.cfg.source_class_name;
    let spi_name = match ctx.cfg.source_class_name.as_str() {
        "CThostFtdcMdApi" => "CThostFtdcMdSpi",
        "CThostFtdcTraderApi" => "CThostFtdcTraderSpi",
        _ => panic!("invalid target class name {}", &ctx.cfg.source_class_name),
    };
    let spi_file = &ctx.cfg.wrap_spi_trait.to_ascii_lowercase();
    let header = format!(
        r#"/* generated by handle_module_api */
use std::{{
    cell::Cell,
    ffi::{{CStr, CString}},
    os::raw::c_char,
    path::Path,
    ptr::null_mut,
    sync::atomic::{{AtomicBool, Ordering}},
}};

use libloading::Library;

use crate::{version}::bindings::*;
use crate::{version}::{spi_file}::*;    
"#,
    );
    let method_data = items
        .iter()
        .filter(|x| !x[0].is_empty())
        .map(|x| x[0].as_str())
        .collect::<Vec<_>>()
        .join("\n");
    let api_trait_code = format!(
        r#"{header}
#[derive(Debug)]
pub struct {trait_name} {{
    pub api_ptr: *mut {api_class},
    pub spi_ptr: Cell<* mut {spi_name}Ext>,
    pub dynlib: Option<Library>,          
    pub released: AtomicBool,
}}

unsafe impl Sync for {trait_name} {{}}
unsafe impl Send for {trait_name} {{}}

impl {trait_name} {{
    {method_declare}
}}
    "#,
        method_declare = method_data,
    );
    api_trait_code
}

pub fn handle_module_spi_trait(ctx: &Context, e: &Entity, items: &ItemVec) -> String {
    let spi_trait = &ctx.cfg.generate_trait_name;

    let method_data = items
        .iter()
        .filter(|x| !x[0].is_empty())
        .map(|x| x[0].as_str())
        .collect::<Vec<_>>()
        .join("\n");

    let spi_trait_code = format!(
        r#"
pub trait {spi_trait}: Send {{{method_code}
}}"#,
        method_code = method_data,
    );
    spi_trait_code
}

pub fn handle_module_vtable_struct(ctx: &Context, e: &Entity, items: &ItemVec) -> String {
    let trait_name = &ctx.cfg.generate_trait_name;

    let method_data = items
        .iter()
        .filter(|x| !x[0].is_empty())
        .map(|x| x[0].as_str())
        .collect::<Vec<_>>()
        .join("\n");

    let vtable_func_code = format!(
        r#"
#[repr(C)]
#[derive(Debug)]
pub struct {trait_name}VTable {{
{fn_declare_list}
}}"#,
        fn_declare_list = method_data
    );
    vtable_func_code
}

pub fn handle_module_static_table(ctx: &Context, e: &Entity, items: &ItemVec) -> String {
    let source_class = &ctx.cfg.source_class_name;
    let trait_name = &ctx.cfg.generate_trait_name;

    let method_data = items
        .iter()
        .filter(|x| !x[0].is_empty())
        .map(|x| x[0].as_str())
        .collect::<Vec<_>>()
        .join("\n");

    let static_table_code = format!(
        r#"
static SPI_VTABLE: {trait_name}VTable = {trait_name}VTable {{
{fn_member_list} 
}};

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

impl {source_class}Ext {{
    pub fn new(spi: *mut dyn {trait_name}) -> Self {{
        Self {{
            vtable: &SPI_VTABLE,
            spi_ptr: spi,
        }}
    }}
}}
"#,
        fn_member_list = method_data
    );
    static_table_code
}

pub fn handle_module_extern_cfn(ctx: &Context, e: &Entity, items: &ItemVec) -> String {
    let method_data = items
        .iter()
        .filter(|x| !x[0].is_empty())
        .map(|x| x[0].as_str())
        .collect::<Vec<_>>()
        .join("\n");

    let spi_cfunc_code = format!(r#"{spi_funcs}"#, spi_funcs = method_data,);
    spi_cfunc_code
}

pub fn handle_module_event_enum(ctx: &Context, e: &Entity, items: &ItemVec) -> String {
    let spi_trait = &ctx.cfg.generate_trait_name;

    let method_data = items
        .iter()
        .filter(|x| !x[0].is_empty())
        .map(|x| x[0].as_str())
        .collect::<Vec<_>>()
        .join("\n");

    let event_enum_code = format!(
        r#"
#[derive(Clone, Debug)]
pub enum {spi_trait}Event {{
{event_enums}
}}
    "#,
        event_enums = method_data
    );
    event_enum_code
}

pub fn handle_module_event_struct(ctx: &Context, e: &Entity, items: &ItemVec) -> String {
    let method_data = items
        .iter()
        .filter(|x| !x[0].is_empty())
        .map(|x| x[0].as_str())
        .collect::<Vec<_>>()
        .join("\n");
    method_data
}

pub fn _convert_api_registerspi_func(ctx: &Context, e: &Entity, params: &ParamVec) -> String {
    let method_call = e.get_name().unwrap();
    let method_name = match &ctx.cfg.method_to_snake {
        true => rustify_method_name2(&method_call),
        _ => method_call.clone(),
    };
    let comment = match &ctx.cfg.generate_comments {
        true => e.get_comment().unwrap_or("".to_string()),
        _ => "".to_string(),
    };
    let api_class = &ctx.cfg.source_class_name;
    let arg_0_name = &params[0].0;
    let spi_name = match ctx.cfg.source_class_name.as_str() {
        "CThostFtdcMdApi" => "CThostFtdcMdSpi",
        "CThostFtdcTraderApi" => "CThostFtdcTraderSpi",
        _ => panic!("invalid target class name {}", &ctx.cfg.source_class_name),
    };

    let self_text = match &ctx.cfg.prefer_self_mut_ref {
        true => "&mut self",
        _ => "&self",
    };
    let mut unsafe_code: String;
    let mut args_code: String;

    if ctx.cfg.wrap_api_struct {
        unsafe_code = format!(
            r#"
        let spi_ptr = Box::into_raw(Box::new({spi_name}Ext::new({arg_0_name})));
        let last_spi_ptr = self.spi_ptr.get();
        unsafe {{
            ((*(*self.api_ptr).vtable_).{api_class}_RegisterSpi)(self.api_ptr, spi_ptr as _)
        }}
        self.spi_ptr.set(spi_ptr);
        if !last_spi_ptr.is_null() {{
            unsafe {{
                let _ = Box::from_raw(last_spi_ptr); // 释放动态分配的内存
            }}
        }}"#,
            spi_name = spi_name
        );
        args_code = format!(
            "{self_text}, {arg_0_name}: *mut dyn {}",
            &ctx.cfg.wrap_spi_trait
        );
    } else {
        unsafe_code = format!(
            r#"
        unsafe {{
            ((*(*self).vtable_).{api_class}_RegisterSpi)(self as *mut {api_class}, {arg_0_name})
        }}"#,
        );
        args_code = format!("&mut self, {arg_0_name}: *mut {spi_name}");
    }
    format!(
        r#"    {comment}
    pub fn {method_name}({args_code}) {{{unsafe_code}
    }}
    "#
    )
}

pub fn _convert_api_incomplete_array_func(ctx: &Context, e: &Entity, params: &ParamVec) -> String {
    // println!("incomplete_array: {:?}", params);
    let method_call = e.get_name().unwrap();
    let method_name = match &ctx.cfg.method_to_snake {
        true => rustify_method_name2(&method_call),
        _ => method_call.clone(),
    };
    let comment = match &ctx.cfg.generate_comments {
        true => e.get_comment().unwrap_or("".to_string()),
        _ => "".to_string(),
    };
    let (result_text, _) = convert_result_rust_type(
        ctx,
        e.get_result_type().unwrap().get_display_name().as_str(),
    );

    let self_text = match &ctx.cfg.prefer_self_mut_ref {
        true => "&mut self",
        _ => "&self",
    };
    let (self_p0, self_p1) = if ctx.cfg.wrap_api_struct {
        ("self.api_ptr".to_string(), "self.api_ptr".to_string())
    } else {
        (
            "self".to_string(),
            format!("self as *mut {}", ctx.cfg.source_class_name),
        )
    };
    let api_class = &ctx.cfg.source_class_name;
    let (arg_0_name, arg_0_type, param_0_call) = (&params[0]);
    let args_text = format!("{self_text}, {arg_0_name}: {arg_0_type}");

    let unsafe_code = if ctx.cfg.prefer_param_cffi_type {
        format!(
            r#"
        unsafe {{
            ((*(*{self_p0}).vtable_).{api_class}_{method_call})({self_p1}, {param_0_call}, {arg_0_name}.len() as i32)
        }}"#,
        )
    } else {
        format!(
            r#"
        let cstrings: Vec<_> = {arg_0_name}.iter().map(|x| CString::new(x.clone()).unwrap()).collect();
        let cstr_slice: Vec<*const i8> = cstrings.iter().map(|cstr| cstr.as_ptr()).collect();
        unsafe {{
            ((*(*{self_p0}).vtable_).{api_class}_{method_call})({self_p1}, cstr_slice.as_ptr() as *mut *mut i8, {arg_0_name}.len() as i32)
        }}"#,
        )
    };

    format!(
        r#"    {comment}
    pub fn {method_name}({args_text}){result_text}{{{unsafe_code}    
    }}
    "#
    )
}
pub fn _convert_api_char_s_func(ctx: &Context, e: &Entity, params: &ParamVec) -> String {
    let method_call = e.get_name().unwrap();
    let method_name = match &ctx.cfg.method_to_snake {
        true => rustify_method_name2(&method_call),
        _ => method_call.clone(),
    };
    let comment = match &ctx.cfg.generate_comments {
        true => e.get_comment().unwrap_or("".to_string()),
        _ => "".to_string(),
    };
    let api_class = &ctx.cfg.source_class_name;
    let self_text = match &ctx.cfg.prefer_self_mut_ref {
        true => "&mut self",
        _ => "&self",
    };
    let (self_p0, self_p1) = if ctx.cfg.wrap_api_struct {
        ("self.api_ptr".to_string(), "self.api_ptr".to_string())
    } else {
        (
            "self".to_string(),
            format!("self as *mut {}", ctx.cfg.source_class_name),
        )
    };
    let (ref arg0, ref type0, ref param0) = params[0];
    let args_text = format!("{self_text}, {arg0}: {type0}");
    let unsafe_code = if ctx.cfg.prefer_param_cffi_type {
        format!(
            r#"
        unsafe {{
            ((*(*{self_p0}).vtable_).{api_class}_{method_call})(self.{self_p1}, {param0})
        }}"#
        )
    } else {
        format!(
            r#"
        unsafe {{
            let {arg0} = CString::new({arg0}).unwrap();
            ((*(*{self_p0}).vtable_).{api_class}_{method_call})({self_p1}, {arg0}.as_ptr() as *mut i8)
        }}"#
        )
    };
    format!(
        r#"    {comment}
    pub fn {method_name}({args_text}) {{{unsafe_code}
    }}
    "#
    )
}
pub fn _convert_api_general_func(ctx: &Context, e: &Entity, params: &ParamVec) -> String {
    let method_call = e.get_name().unwrap();
    let method_name = match &ctx.cfg.method_to_snake {
        true => rustify_method_name2(&method_call),
        _ => method_call.clone(),
    };
    let comment = match &ctx.cfg.generate_comments {
        true => e.get_comment().unwrap_or("".to_string()),
        _ => "".to_string(),
    };
    let (result_text, result_type) = convert_result_rust_type(
        ctx,
        e.get_result_type().unwrap().get_display_name().as_str(),
    );
    let api_class = &ctx.cfg.source_class_name;

    let self_text = match &ctx.cfg.prefer_self_mut_ref {
        true => "&mut self",
        _ => "&self",
    };
    let (self_p0, self_p1) = if ctx.cfg.wrap_api_struct {
        ("self.api_ptr".to_string(), "self.api_ptr".to_string())
    } else {
        (
            "self".to_string(),
            format!("self as *mut {}", ctx.cfg.source_class_name),
        )
    };

    let mut arg_vec = params
        .iter()
        .map(|x| format!("{}: {}", x.0, x.1))
        .collect::<Vec<String>>();
    arg_vec.insert(0, self_text.to_string());
    let args_text = arg_vec.join(", ");

    let mut param_vec = params
        .iter()
        .map(|x| format!("{}", x.2))
        .collect::<Vec<String>>();
    param_vec.insert(0, self_p1.to_string());
    let params_text = param_vec.join(", ");

    let is_char_s_func =
        if params.len() == 1 && (params[0].1 == "&std::ffi::CString" || params[0].1 == "&str") {
            true
        } else {
            false
        };
    let unsafe_code = match (is_char_s_func, result_type) {
        (true, TypeKind::Void) => match ctx.cfg.prefer_param_cffi_type {
            true => {
                let (ref arg0, _, ref param0) = params[0];
                format!(
                    r#"
        unsafe {{
            ((*(*{self_p0}).vtable_).{api_class}_{method_call})(self.{self_p1}, {param0})
        }}"#
                )
            }
            _ => {
                let (ref arg0, _, ref param0) = params[0];
                format!(
                    r#"
        unsafe {{
            let {arg0} = CString::new({arg0}).unwrap();
            ((*(*{self_p0}).vtable_).{api_class}_{method_call})(self.{self_p1}, {arg0}.as_ptr() as *mut i8)
        }}"#
                )
            }
        },
        (false, TypeKind::CharS) => match ctx.cfg.prefer_param_cffi_type {
            true => format!(
                r#"
        unsafe {{
            ((*(*{self_p0}).vtable_).{api_class}_{method_call})({self_p1})
        }}"#
            ),
            _ => format!(
                r#"
        unsafe {{
            let cstr_ptr = ((*(*{self_p0}).vtable_).{api_class}_{method_call})({self_p1});
            let c_str = CStr::from_ptr(cstr_ptr);
            c_str.to_string_lossy().to_string()
        }}"#
            ),
        },
        _ => {
            format!(
                r#"
        unsafe {{
            ((*(*{self_p0}).vtable_).{api_class}_{method_call})({params_text})
        }}"#
            )
        }
    };

    format!(
        r#"    {comment}
    pub fn {method_name}({args_text}){result_text}{{{unsafe_code}
    }}
    "#
    )
}

pub fn _convert_api_release_func(ctx: &Context, e: &Entity, params: &ParamVec) -> String {
    let method_call = e.get_name().unwrap();
    let method_name = match &ctx.cfg.method_to_snake {
        true => rustify_method_name2(&method_call),
        _ => method_call.clone(),
    };
    let api_class = &ctx.cfg.source_class_name;
    let comment = match &ctx.cfg.generate_comments {
        true => e.get_comment().unwrap_or("".to_string()),
        _ => "".to_string(),
    };

    let self_text = match &ctx.cfg.prefer_self_mut_ref {
        true => "&mut self",
        _ => "&self",
    };
    let (self_p0, self_p1) = if ctx.cfg.wrap_api_struct {
        ("self.api_ptr".to_string(), "self.api_ptr".to_string())
    } else {
        (
            "self".to_string(),
            format!("self as *mut {}", ctx.cfg.source_class_name),
        )
    };
    let mut arg_vec = params
        .iter()
        .map(|x| format!("{}: {}", x.0, x.1))
        .collect::<Vec<String>>();
    arg_vec.insert(0, self_text.to_string());
    let args_text = arg_vec.join(", ");

    let mut param_vec = params
        .iter()
        .map(|x| format!("{}", x.2))
        .collect::<Vec<String>>();
    param_vec.insert(0, self_p1.to_string());
    let params_text = param_vec.join(", ");

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

pub fn convert_api_trait_func_(ctx: &Context, e: &Entity, params: &ParamVec) -> Vec<String> {
    let func_name = e.get_name().unwrap();

    if func_name.contains("Subscribe") && params[0].1.contains("[String]") {
        return vec![_convert_api_incomplete_array_func(ctx, e, params)];
    }

    let func_code = match func_name.as_str() {
        "RegisterFront" | "RegisterNameServer" => _convert_api_char_s_func(ctx, e, params),
        "RegisterSpi" => _convert_api_registerspi_func(ctx, e, params),
        "Release" => _convert_api_release_func(ctx, e, params),
        _ => _convert_api_general_func(ctx, e, params),
    };
    vec![func_code]
}

pub fn convert_spi_trait_func_(ctx: &Context, e: &Entity, params: &ParamVec) -> Vec<String> {
    let method_call = e.get_name().unwrap();
    let method_name = match ctx.cfg.method_to_snake {
        true => rustify_method_name2(&method_call),
        false => method_call.clone(),
    };
    let comment = match ctx.cfg.generate_comments {
        true => e.get_comment().unwrap_or("".to_string()),
        _ => "".to_string(),
    };

    let mut arg_vec = params
        .iter()
        .map(|x| format!("{}: {}", x.0, x.1))
        .collect::<Vec<String>>();
    if ctx.cfg.prefer_self_mut_ref {
        arg_vec.insert(0, "&mut self".to_string());
    } else {
        arg_vec.insert(0, "&self".to_string());
    }

    let trait_method_code = format!(
        r#"   
    {comment}
    fn {method_name}({arg_list}) {{
    }}"#,
        arg_list = arg_vec.join(", "),
    );
    vec![trait_method_code]
}

pub fn convert_spi_vtable_struct_(ctx: &Context, e: &Entity, params: &ParamVec) -> Vec<String> {
    let method_call = e.get_name().unwrap();
    let method_name = match ctx.cfg.method_to_snake {
        true => rustify_method_name2(&method_call),
        false => method_call.clone(),
    };

    let mut arg_vec = params
        .iter()
        .map(|x| format!("{}: {}", x.0, x.1))
        .collect::<Vec<String>>();

    arg_vec.insert(0, format!("spi: *mut {}Ext", ctx.cfg.source_class_name));

    let vtable_func_code = format!(
        r#"    {method_name}: unsafe extern "C" fn({}),"#,
        arg_vec.join(", ")
    );
    vec![vtable_func_code]
}

pub fn convert_spi_static_vtable_(ctx: &Context, e: &Entity, params: &ParamVec) -> Vec<String> {
    let method_call = e.get_name().unwrap();
    let method_name = match ctx.cfg.method_to_snake {
        true => rustify_method_name2(&method_call),
        false => method_call.clone(),
    };

    let vtable_func_code = format!(r#"    {method_name}: spi_{method_name},"#,);
    vec![vtable_func_code]
}

pub fn convert_spi_cfunc_(ctx: &Context, e: &Entity, params: &ParamVec) -> Vec<String> {
    let method_call = e.get_name().unwrap();
    let method_name = match ctx.cfg.method_to_snake {
        true => rustify_method_name2(&method_call),
        false => method_call.clone(),
    };
    let self_ptr = format!("spi: *mut {}Ext", &ctx.cfg.source_class_name);
    let mut arg_vec = params
        .iter()
        .map(|x| format!("{}: {}", x.0, x.1))
        .collect::<Vec<_>>();
    arg_vec.insert(0, self_ptr);

    let params_ = params
        .iter()
        .map(|x| format!("{}", x.2))
        .collect::<Vec<_>>()
        .join(", ");

    let spi_cfunc_code = format!(
        r#"
extern "C" fn spi_{method_name}({}) {{
    unsafe {{
        (*(*spi).spi_ptr).{method_name}({params_})
    }}
}}"#,
        arg_vec.join(", ")
    );
    vec![spi_cfunc_code]
}

pub fn convert_spi_event_enum_(ctx: &Context, e: &Entity, params: &ParamVec) -> Vec<String> {
    let trait_name = &ctx.cfg.wrap_spi_trait;
    let method_call = e.get_name().unwrap();
    let event_enum_entry = format!("    {method_call}({trait_name}{method_call}Event),");
    vec![event_enum_entry]
}

pub fn convert_spi_event_struct_(ctx: &Context, e: &Entity, params: &ParamVec) -> Vec<String> {
    let trait_name = &ctx.cfg.wrap_spi_trait;
    let method_call = e.get_name().unwrap();
    let (to_snake, trim_prefix) = (&ctx.cfg.param_to_snake, &ctx.cfg.param_trim_prefix);
    let event_entries = params
        .iter()
        .map(|x| {
            let pn = normalize_param_name2(&x.0, *to_snake, *trim_prefix);
            format!("    pub {}: {},", pn, x.1)
        })
        .collect::<Vec<_>>()
        .join("\n");
    let v = format!(
        r#"
#[derive(Clone, Debug)]
pub struct {trait_name}{method_call}Event {{
{event_entries}
}}"#,
    );
    vec![v]
}

pub fn convert_param_type(ctx: &Context, e: &Entity) -> (String, String, String) {
    // let cfg = &ctx.cfg;
    let tp = e.get_type().unwrap();
    let tk = tp.get_kind();
    let pn = e.get_name().unwrap();
    let tn = tp.get_display_name();

    match tk {
        TypeKind::Int | TypeKind::Bool | TypeKind::Enum => {
            let handler = ctx.params.get(&tk).unwrap();
            handler(ctx, &pn, &tn, &tk)
        }
        TypeKind::Elaborated => {
            let ct = tp.get_canonical_type();
            let ctk = ct.get_kind();
            let ctn = ct.get_display_name();
            match ctk {
                TypeKind::Enum => {
                    let handler = ctx.params.get(&TypeKind::Enum).unwrap();
                    handler(ctx, &pn, &tn, &ctk)
                }
                TypeKind::ConstantArray => convert_constant_array_type_(ctx, &pn, &tn, &ctk),
                TypeKind::Pointer => {
                    let handler = ctx.params.get(&(TypeKind::Pointer)).unwrap();
                    handler(ctx, &pn, &ctn, &ctk)
                }
                _ => (pn.clone(), tn, pn),
            }
        }
        TypeKind::Pointer => {
            let pt = tp.get_pointee_type().unwrap();
            let ptk = pt.get_kind();
            let ptn = pt.get_display_name();
            match ptk {
                TypeKind::CharS => {
                    let handler = ctx.params.get(&ptk).unwrap();
                    handler(ctx, &pn, &tn, &ptk)
                }
                TypeKind::Pointer | TypeKind::Elaborated | TypeKind::Record => {
                    let handler = ctx.params.get(&(TypeKind::Pointer)).unwrap();
                    handler(ctx, &pn, &ptn, &ptk)
                }
                _ => panic!("_ => {}: {} {:?}", tn, pt.get_display_name(), pt.get_kind()),
            }
        }
        TypeKind::IncompleteArray => {
            let handler = ctx.params.get(&tk).unwrap();
            handler(ctx, &pn, &tn, &tk)
        }
        _ => unimplemented!(),
    }
}

pub fn convert_pointee_type(
    ctx: &Context,
    pn: &str,
    tn: &str,
    tk: &TypeKind,
) -> (String, String, String) {
    let pn = normalize_param_name2(pn, ctx.cfg.param_to_snake, ctx.cfg.param_trim_prefix);
    match (&ctx.cfg.prefer_pointer, &ctx.cfg.module_flavor) {
        (PointerStyle::RawPointerMut, ModuleFlavor::SpiTrait) => {
            (pn.clone(), format!("Option<&{}>", tn), pn)
        }
        (PointerStyle::RawPointerMut, ModuleFlavor::ExternCFn) => (
            pn.clone(),
            format!("*mut {}", tn),
            format!("{}.as_ref()", pn),
        ),
        (PointerStyle::RawPointerMut, ModuleFlavor::EventEnumStruct) => {
            (pn.clone(), format!("Option<{}>", tn), format!("{}", pn))
        }
        (PointerStyle::RawPointerMut, ModuleFlavor::SpiFn) => (
            pn.clone(),
            format!("Option<&{}>", tn),
            format!("{}.cloned()", pn),
        ),
        (PointerStyle::RawPointerMut, _) => (pn.clone(), format!("*mut {}", tn), format!("{}", pn)),
        (PointerStyle::RawPointerConst, ModuleFlavor::SpiTrait) => {
            (pn.clone(), format!("Option<&{}>", tn), pn)
        }
        (PointerStyle::RawPointerConst, ModuleFlavor::ExternCFn) => (
            pn.clone(),
            format!("*const {}", tn),
            format!("{}.as_ref()", pn),
        ),
        (PointerStyle::RawPointerConst, ModuleFlavor::EventEnumStruct) => {
            (pn.clone(), format!("Option<{}>", tn), format!("{}", &pn))
        }
        (PointerStyle::RawPointerConst, ModuleFlavor::SpiFn) => (
            pn.clone(),
            format!("Option<&{}>", tn),
            format!("{}.cloned()", pn),
        ),
        (PointerStyle::RawPointerConst, _) => (
            pn.clone(),
            format!("*const {}", tn),
            format!("{} as *mut {}", &pn, tn),
        ),

        (PointerStyle::MutRef, ModuleFlavor::SpiTrait) => (
            pn.clone(),
            format!("&{}mut {}", &ctx.cfg.life_time, tn),
            format!("{}", &pn),
        ),
        (PointerStyle::MutRef, ModuleFlavor::VTableStruct) => {
            (pn.clone(), format!("*mut {}", tn), format!("{}", pn))
        }
        (PointerStyle::MutRef, ModuleFlavor::ExternCFn) => (
            pn.clone(),
            format!("*mut {}", tn),
            format!("&{}mut *{}", &ctx.cfg.life_time, tn),
        ),
        (PointerStyle::MutRef, ModuleFlavor::EventEnumStruct) => (
            pn.clone(),
            format!("&{} {}", &ctx.cfg.life_time, tn),
            format!("{}", &pn),
        ),

        (PointerStyle::MutRef, _) => (
            pn.clone(),
            format!("&{}mut {}", &ctx.cfg.life_time, tn),
            format!("{} as *mut {}", &pn, tn),
        ),

        (PointerStyle::Ref, ModuleFlavor::SpiTrait) => (
            pn.clone(),
            format!("&{} {}", &ctx.cfg.life_time, tn),
            format!("{}", &pn),
        ),
        (PointerStyle::Ref, ModuleFlavor::VTableStruct) => {
            (pn.clone(), format!("*const {}", tn), format!("{}", pn))
        }
        (PointerStyle::Ref, ModuleFlavor::ExternCFn) => {
            (pn.clone(), format!("*const {}", tn), format!("& *{}", &pn))
        }
        (PointerStyle::Ref, ModuleFlavor::EventEnumStruct) => (
            pn.clone(),
            format!("&{} {}", &ctx.cfg.life_time, tn),
            format!("{}", &pn),
        ),
        (PointerStyle::Ref, _) => (
            pn.clone(),
            format!("&{} {}", &ctx.cfg.life_time, tn),
            format!("{} as *const {} *mut {}", &pn, tn, tn),
        ),

        _ => panic!("invalid pointer style {:?}", &ctx.cfg.prefer_pointer),
    }
}

pub fn convert_constant_array_type_(
    ctx: &Context,
    pn: &str,
    tn: &str,
    tk: &TypeKind,
) -> (String, String, String) {
    let pn = normalize_param_name2(pn, ctx.cfg.param_to_snake, ctx.cfg.param_trim_prefix);
    (
        pn.clone(),
        tn.to_string(),
        format!("{}.as_ptr() as *mut i8", pn),
    )
}

pub fn convert_base_type_(
    ctx: &Context,
    pn: &str,
    tn: &str,
    tk: &TypeKind,
) -> (String, String, String) {
    let pn = normalize_param_name2(pn, ctx.cfg.param_to_snake, ctx.cfg.param_trim_prefix);
    let type_text = match (tk, ctx.cfg.prefer_param_cffi_type) {
        (TypeKind::Int, true) => "std::os::raw::c_int".to_string(),
        (TypeKind::Int, false) => "i32".to_string(),
        (TypeKind::Bool, _) => "bool".to_string(),
        (TypeKind::Enum, _) => tn.to_string(),
        _ => panic!("Unknown {:?}", tk),
    };

    (format!("{}", pn), type_text, format!("{}", pn))
}

pub fn convert_incomplete_array(
    ctx: &Context,
    pn: &str,
    tn: &str,
    tk: &TypeKind,
) -> (String, String, String) {
    let pn = normalize_param_name2(pn, ctx.cfg.param_to_snake, ctx.cfg.param_trim_prefix);
    let (type_text, param_call) = match &ctx.cfg.prefer_param_cffi_type {
        true => (
            format!("&Vec<std::ffi::CString>"),
            format!(
                "{}.iter().map(|cs| cs.as_ptr()).collect::<Vec<_>>().as_mut_ptr() as *mut *mut i8",
                pn,
            ),
        ),
        false => (format!("&[String]"), format!(".as_ptr() as *mut *mut i8")),
    };
    (pn, type_text, param_call)
}

pub fn convert_char_s_type_(
    ctx: &Context,
    pn: &str,
    tn: &str,
    tk: &TypeKind,
) -> (String, String, String) {
    let pn = normalize_param_name2(pn, ctx.cfg.param_to_snake, ctx.cfg.param_trim_prefix);
    let (type_text, param_call) = match &ctx.cfg.prefer_param_cffi_type {
        true => (
            format!("&std::ffi::CString"),
            format!("{}.as_ptr() as *mut i8", pn),
        ),
        false => (format!("&str"), format!("{}.as_ptr() as *mut i8", pn)),
    };
    (pn, type_text, param_call)
}

pub fn convert_result_rust_type(ctx: &Context, result: &str) -> (String, TypeKind) {
    let prefer_cffi_type = &ctx.cfg.prefer_param_cffi_type;
    match (result, prefer_cffi_type) {
        ("void", _) => (" ".to_string(), TypeKind::Void),
        ("int", true) => (" -> std::os::raw::c_int ".to_string(), TypeKind::Int),
        ("int", false) => (" -> i32 ".to_string(), TypeKind::Int),
        ("const char *", true) => (
            " -> *const std::os::raw::c_char ".to_string(),
            TypeKind::CharS,
        ),
        ("const char *", false) => (" -> String ".to_string(), TypeKind::CharS),
        _ => panic!("Unknown {:?}", result),
    }
}

pub fn rustify_method_name2(method_name: &str) -> String {
    method_name.replace("UnSub", "Unsub").to_snake_case()
}

pub fn normalize_param_name2(arg: &str, to_snake: bool, trim_prefix: bool) -> String {
    match (to_snake, trim_prefix) {
        (true, true) => strip_prefix_set(arg.to_snake_case().as_str()),
        (true, false) => arg.to_snake_case(),
        _ => arg.to_string(),
    }
}

fn strip_prefix_set(input: &str) -> String {
    let prefixes = ["psz_", "p_", "n_", "b_"];
    for prefix in prefixes {
        if let Some(stripped) = input.strip_prefix(prefix) {
            return stripped.to_string();
        }
    }
    input.into() // 如果没有匹配任何前缀，返回原字符串
}
