use crate::callback::Callback;
use crate::dom::element::DomElement;

impl DomElement {
    /// Attach an event listener to this DOM element.
    ///
    /// TODO: We are still experimenting with event handling so we currently have multiple methods
    ///  in this file for adding event listeners. We can eventually figure out our patterns,
    ///  document these patterns, then delete methods that do not fit within these patterns.
    // IDEA: The context should only be `&'static Callback` if the component's `handle_event`
    //  exported function is expecting that type.
    //  So perhaps we make the `handle_events_using_callbacks!` macro create some constant value, and
    //  then to call `add_event_listener` with `&'static Callback` you need to also pass in that
    //  value. This way you can only call `.add_event_listener` with a `&'static Callback` if you
    //  also initialized a handler using the `handle_events_using_callbacks!` macro.
    //  Then if you don't want to use that macro you'd have to use your own `isize` context instead
    //  of using the convenient helper function that takes `&'static Callback` and the type that
    //  the macro generated.
    //  So, in short, this add event listener method would take `SomeType` and `SomeType` would only
    //  be creatable using the `handle_events_using_callbacks!` macro which calls all `#[doc(hidden)]`
    //  constructor such as `SomeType::_private_new()`. Then you can still register an event listener
    //  without using this abstraction by just passing your own custom `isize` context.
    //  Just an idea ... would need to feel out the ergonomics ...
    pub fn add_event_listener_with_callback(
        &self,
        event_name: &str,
        context: &'static Callback,
    ) -> i64 {
        unsafe {
            afia_component_sys::dom_element_add_event_listener(
                self.component_imports_ptr(),
                self.to_i64(),
                event_name.as_ptr(),
                event_name.len(),
                context as *const Callback as isize,
            )
        }
    }

    /// Attach an event listener to a DOM element.
    ///
    /// TODO: We are still experimenting with event handling so we currently have multiple methods
    ///  in this file for adding event listeners. We can eventually figure out our patterns,
    ///  document these patterns, then delete methods that do not fit within these patterns.
    pub fn add_event_listener_boxed(&self, event_name: &str, callback: Box<dyn FnMut()>) -> i64 {
        let callback_raw = Box::into_raw(Box::new(callback));

        unsafe {
            afia_component_sys::dom_element_add_event_listener(
                self.component_imports_ptr(),
                self.to_i64(),
                event_name.as_ptr(),
                event_name.len(),
                callback_raw as *mut () as isize,
            )
        }
    }
}
