macro_rules! event_handler_body {
    (
        $env:ident, $handler:ident, $event_container:expr, $function_js_name:literal, $function_rust_name:ident($event_type:ty)
    ) => {
        let extension_context = crate::vscode_sys::VscodeContext::extension_context($env)?;
        let mut subscriptions: bindgen_prelude::Array =
            extension_context.get_named_property("subscriptions")?;

        let event_creator: bindgen_prelude::Function<
            bindgen_prelude::Function<$event_type, ()>,
            // TODO: disposable
            bindgen_prelude::Object,
        > = $event_container.get_named_property($function_js_name)?;
        let event_handler_fn: bindgen_prelude::Function<$event_type, ()> = $env
            .create_function_from_closure($function_js_name, move |function_context| {
                let parent_span = tracing::span!(tracing::Level::TRACE, "event_handler");
                let _entered_span = parent_span.enter();

                let event = match function_context.args::<($event_type,)>() {
                    Ok((event,)) => event,
                    Err(error) => {
                        tracing::error!(
                            message = "Invalid arguments provided to event handler",
                            event_handler = $function_js_name,
                            ?error
                        );

                        return Err(napi::Error::from_reason(
                            "Invalid arguments provided to event handler",
                        ));
                    }
                };

                match std::panic::catch_unwind(|| $handler(function_context.env, event)) {
                    Ok(handler_result) => match handler_result {
                        Ok(result) => Ok(result),
                        Err(error) => {
                            tracing::error!(
                                message = "Event handler returned an error",
                                event_handler = $function_js_name,
                                ?error
                            );

                            Err(napi::Error::from_reason("Event handler returned an error"))
                        }
                    },
                    Err(panic_payload) => {
                        tracing::error!(
                            message = "Event handler panicked",
                            event_handler = $function_js_name,
                            ?panic_payload
                        );

                        Err(napi::Error::from_reason("Event handler panicked"))
                    }
                }
            })?;

        let handler_subscription: bindgen_prelude::Object = event_creator.call(event_handler_fn)?;
        subscriptions.insert(handler_subscription)?;

        Ok(())
    };
}

pub(crate) use event_handler_body;