use serde_wasm_bindgen::{from_value, to_value};
use wasm_bindgen::prelude::*;

// 说明：复用 mnote-web 当前 tree shell runtime 源码，避免复制第二份 reducer 真相。
pub mod tree_shell {
    pub mod drag_drop_state {
        include!(concat!(
            env!("CARGO_MANIFEST_DIR"),
            "/../mnote-web/src/tree_shell/drag_drop_state.rs"
        ));
    }
    pub mod filetree_runtime {
        include!(concat!(
            env!("CARGO_MANIFEST_DIR"),
            "/../mnote-web/src/tree_shell/filetree_runtime.rs"
        ));
    }
    pub mod filetree_selection {
        include!(concat!(
            env!("CARGO_MANIFEST_DIR"),
            "/../mnote-web/src/tree_shell/filetree_selection.rs"
        ));
    }
    pub mod focus_state {
        include!(concat!(
            env!("CARGO_MANIFEST_DIR"),
            "/../mnote-web/src/tree_shell/focus_state.rs"
        ));
    }
    pub mod page_runtime {
        include!(concat!(
            env!("CARGO_MANIFEST_DIR"),
            "/../mnote-web/src/tree_shell/page_runtime.rs"
        ));
    }
    pub mod picker_runtime {
        include!(concat!(
            env!("CARGO_MANIFEST_DIR"),
            "/../mnote-web/src/tree_shell/picker_runtime.rs"
        ));
    }
    pub mod picker_state {
        include!(concat!(
            env!("CARGO_MANIFEST_DIR"),
            "/../mnote-web/src/tree_shell/picker_state.rs"
        ));
    }
    pub mod runtime_api {
        include!(concat!(
            env!("CARGO_MANIFEST_DIR"),
            "/../mnote-web/src/tree_shell/runtime_api.rs"
        ));
    }
}

fn format_js_error(stage: &str, error: impl std::fmt::Display) -> JsValue {
    JsValue::from_str(&format!("[tree_shell_runtime_wasm:{stage}] {error}"))
}

#[wasm_bindgen(start)]
pub fn install_panic_hook() {
    console_error_panic_hook::set_once();
}

#[wasm_bindgen(js_name = reduceTreeShellRuntime)]
pub fn reduce_tree_shell_runtime_export(request: JsValue) -> Result<JsValue, JsValue> {
    let request = from_value::<tree_shell::runtime_api::TreeShellRuntimeRequest>(request)
        .map_err(|error| format_js_error("decode_request", error))?;
    let result = tree_shell::runtime_api::reduce_tree_shell_runtime(request);
    to_value(&result).map_err(|error| format_js_error("encode_result", error))
}
