pub fn generate(name: &str) -> Result<(), String> {
    let snake = name.to_lowercase().replace(['-', ' '], "_");
    let pascal = to_pascal_case(&snake);

    println!("=== Adding hook event: on_{snake} ===");
    println!();
    println!("Follow these steps to add a new `on_{snake}` hook event.");
    println!();

    // Step 1: Event struct
    println!("--- Step 1: Event struct ---");
    println!("File: crates/quicproquo-server/src/hooks.rs");
    println!();
    println!(
        r#"/// Event data for {snake} operations.
#[derive(Clone, Debug)]
pub struct {pascal}Event {{
    // TODO: add your event fields here
    // Example:
    // pub channel_id: Vec<u8>,
    // pub user_key: Vec<u8>,
}}
"#,
    );

    // Step 2: Trait method
    println!("--- Step 2: Trait method ---");
    println!("File: crates/quicproquo-server/src/hooks.rs");
    println!();
    println!("Add to the `ServerHooks` trait:");
    println!();
    println!(
        r#"    /// Called when {snake} occurs.
    fn on_{snake}(&self, _event: &{pascal}Event) {{
        // Default: no-op
    }}
"#,
    );

    // Step 3: TracingHooks implementation
    println!("--- Step 3: TracingHooks implementation ---");
    println!("File: crates/quicproquo-server/src/hooks.rs");
    println!();
    println!("Add to `impl ServerHooks for TracingHooks`:");
    println!();
    println!(
        r#"    fn on_{snake}(&self, _event: &{pascal}Event) {{
        tracing::info!("hook: {snake}");
    }}
"#,
    );

    // Step 4: Plugin API (C-compatible struct)
    println!("--- Step 4: Plugin API ---");
    println!("File: crates/quicproquo-plugin-api/src/lib.rs");
    println!();
    println!("Add a C-compatible event struct:");
    println!();
    println!(
        r#"#[repr(C)]
pub struct C{pascal}Event {{
    // TODO: mirror the fields from {pascal}Event using C-compatible types
    // Use *const u8 + len for byte slices, *const c_char for strings
}}
"#,
    );
    println!("Add to `HookVTable`:");
    println!();
    println!(
        r#"    pub on_{snake}: Option<extern "C" fn(*mut c_void, *const C{pascal}Event)>,
"#,
    );

    // Step 5: Wire into PluginHooks
    println!("--- Step 5: PluginHooks dispatch ---");
    println!("File: crates/quicproquo-server/src/plugin_loader.rs");
    println!();
    println!("Add to `impl ServerHooks for PluginHooks`:");
    println!();
    println!(
        r#"    fn on_{snake}(&self, event: &{pascal}Event) {{
        if let Some(hook_fn) = self.vtable.on_{snake} {{
            let c_event = C{pascal}Event {{
                // TODO: convert fields
            }};
            hook_fn(self.vtable.user_data, &c_event);
        }}
    }}
"#,
    );

    // Step 6: Call the hook
    println!("--- Step 6: Call the hook in the RPC handler ---");
    println!("In the relevant handler file under crates/quicproquo-server/src/node_service/:");
    println!();
    println!(
        r#"    use crate::hooks::{pascal}Event;

    // At the appropriate point in the handler:
    self.hooks.on_{snake}(&{pascal}Event {{
        // fill in fields
    }});
"#,
    );

    // Step 7: Verify
    println!("--- Step 7: Verify ---");
    println!("  cargo build -p quicproquo-plugin-api");
    println!("  cargo build -p quicproquo-server");
    println!("  cargo test -p quicproquo-server");
    println!();

    // Summary
    println!("=== Files to modify ===");
    println!("  [modify] crates/quicproquo-server/src/hooks.rs");
    println!("  [modify] crates/quicproquo-plugin-api/src/lib.rs");
    println!("  [modify] crates/quicproquo-server/src/plugin_loader.rs");
    println!("  [modify] crates/quicproquo-server/src/node_service/<handler>.rs");

    Ok(())
}

fn to_pascal_case(snake: &str) -> String {
    snake
        .split('_')
        .map(|word| {
            let mut chars = word.chars();
            match chars.next() {
                None => String::new(),
                Some(c) => c.to_uppercase().to_string() + chars.as_str(),
            }
        })
        .collect()
}
