use js_sys::{Array, Function};
use wasm_bindgen::prelude::*;
use crate::{constructors::HTML_ELEMENT_CONSTRUCTOR, Bridge, CustomElement, GeneratedConstructor};
type MakeStruct = Closure<dyn FnMut(JsValue, Array) -> JsValue>;
#[wasm_bindgen(module = "/src/createCustomElement.js")]
extern "C" {
    #[wasm_bindgen(js_name = createCustomElement)]
    pub(self) fn _create_custom_element(
        make_rust_struct: &MakeStruct,
        attributes: Vec<String>,
        constructor: &Function,
    ) -> Function;
}
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub struct CustomElementConfiguration<'a> {
    pub element_constructor: &'a Function,
}
impl<'a> Default for CustomElementConfiguration<'a> {
    fn default() -> Self {
        Self {
            element_constructor: &HTML_ELEMENT_CONSTRUCTOR,
        }
    }
}
pub struct CustomElementResult {
    pub constructor: GeneratedConstructor,
    pub closure: MakeStruct,
}
pub fn create_custom_element<
    C: CustomElement + 'static,
    F: FnMut(JsValue, Array) -> C + 'static,
>(
    create_cutom_element: F,
    attributes: Vec<String>,
) -> (MakeStruct, GeneratedConstructor) {
    let config = CustomElementConfiguration::default();
    create_custom_element_with_config(create_cutom_element, attributes, config)
}
pub fn create_custom_element_with_config<
    C: CustomElement + 'static,
    F: FnMut(JsValue, Array) -> C + 'static,
>(
    mut create_cutom_element: F,
    attributes: Vec<String>,
    config: CustomElementConfiguration,
) -> (MakeStruct, GeneratedConstructor) {
    let closure = Closure::new(move |element, args| {
        let bridge: Bridge = create_cutom_element(element, args).into();
        bridge.into()
    });
    let class = _create_custom_element(&closure, attributes, config.element_constructor);
    (closure, GeneratedConstructor(class))
}