use crate::core::config::TraitBridgeConfig;
use crate::core::ir::TypeDef;

pub fn gen_typescript_trait_bridge_files(bridges: &[(String, &TraitBridgeConfig, &TypeDef)]) -> Vec<(String, String)> {
    let mut files = Vec::new();

    for (trait_name, bridge_cfg, trait_def) in bridges {
        // Skip if function_param binding is not used (only Path A uses function_param)
        if !matches!(bridge_cfg.bind_via, crate::core::config::BridgeBinding::FunctionParam) {
            continue;
        }

        let content = gen_single_typescript_trait_bridge(trait_name, trait_def);
        let filename = format!("{}Bridge.ts", trait_name);
        files.push((filename, content));
    }

    files
}

/// Generate a single TypeScript trait bridge file with interface and adapter class.
fn gen_single_typescript_trait_bridge(trait_name: &str, trait_def: &TypeDef) -> String {
    use heck::ToLowerCamelCase;

    let bridge_interface_name = format!("{}Bridge", trait_name);
    let adapter_class_name = format!("{}Adapter", trait_name);

    let mut interface_methods = String::new();
    let mut adapter_methods = String::new();

    for method in &trait_def.methods {
        let method_camel = method.name.to_lower_camel_case();
        let has_error = method.error_type.is_some();

        // Generate parameter list
        let params = method
            .params
            .iter()
            .map(|p| {
                let param_name = p.name.to_lower_camel_case();
                format!("{}: string", param_name) // All params marshalled as JSON strings at boundary
            })
            .collect::<Vec<_>>()
            .join(", ");

        // Generate return type (all returns are strings for JSON marshalling)
        let return_type = "string";
        let throws_clause = if has_error { " throws" } else { "" };

        // Interface method
        interface_methods.push_str(&format!(
            "  {}{}({}){}: {};\n",
            method_camel,
            if has_error { "?" } else { "" },
            params,
            throws_clause,
            return_type
        ));

        // Adapter method
        let call_args = method
            .params
            .iter()
            .map(|p| format!("\"{}\"", p.name.to_lower_camel_case()))
            .collect::<Vec<_>>()
            .join(", ");

        adapter_methods.push_str(&format!(
            "  async {}({}): Promise<{}> {{\n",
            method_camel, params, return_type
        ));
        adapter_methods.push_str(&format!(
            "    try {{\n      const result = await this.bridge.{}({});\n",
            method_camel, call_args
        ));
        adapter_methods.push_str("      return JSON.stringify({ ok: result });\n");
        adapter_methods.push_str("    } catch (e) {\n");
        adapter_methods.push_str("      return JSON.stringify({ err: String(e) });\n");
        adapter_methods.push_str("    }\n");
        adapter_methods.push_str("  }\n\n");
    }

    // Generate full file content
    let mut content = String::new();
    content.push_str("/**\n");
    content.push_str(" * Generated by alef. Do not edit by hand.\n");
    content.push_str(" * \n");
    content.push_str(" * TypeScript trait bridge for outbound plugin implementations.\n");
    content.push_str(" */\n\n");

    // Interface
    content.push_str(&format!(
        "export interface {} {{\n  name(): string;\n  version(): string;\n  initialize(): Promise<void>;\n  shutdown(): Promise<void>;\n{}}}",
        bridge_interface_name, interface_methods
    ));

    content.push_str("\n\n");

    // Adapter class
    content.push_str(&format!(
        "export class {} {{\n  constructor(private bridge: {}) {{}}\n\n{}}}",
        adapter_class_name, bridge_interface_name, adapter_methods
    ));

    content
}
