use std::sync::Arc;
use wasm_bindgen::prelude::*;
use workflow_core::sendable::Sendable;
pub trait JsErrorExtension {
    fn message(&self) -> String;
}
impl JsErrorExtension for JsError {
    fn message(&self) -> String {
        let inner = JsValue::from(self.clone());
        let msg = js_sys::Reflect::get(&inner, &JsValue::from_str("message"))
            .expect("unable to get error message");
        msg.as_string()
            .expect("unable to convert error message to string")
    }
}
pub trait JsValueErrorTrait {
    fn message(&self) -> String;
}
impl JsValueErrorTrait for JsValue {
    fn message(&self) -> String {
        let msg = js_sys::Reflect::get(self, &JsValue::from_str("message"))
            .expect("unable to get error message");
        msg.as_string()
            .expect("unable to convert error message to string")
    }
}
struct Inner {
    name: Option<String>,
    message: Option<String>,
    cause: Option<String>,
    stack: Option<String>,
    code: Option<String>,
    origin: Sendable<JsValue>,
}
#[derive(Clone)]
pub struct JsErrorData {
    inner: Arc<Inner>,
}
impl std::error::Error for JsErrorData {}
impl JsErrorData {
    pub fn name(&self) -> &Option<String> {
        &self.inner.name
    }
    pub fn message(&self) -> &Option<String> {
        &self.inner.message
    }
    pub fn cause(&self) -> &Option<String> {
        &self.inner.cause
    }
    pub fn stack(&self) -> &Option<String> {
        &self.inner.stack
    }
    pub fn code(&self) -> &Option<String> {
        &self.inner.code
    }
}
impl std::fmt::Debug for JsErrorData {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("JsErrorData")
            .field("name", &self.inner.name)
            .field("message", &self.inner.message)
            .field("cause", &self.inner.cause)
            .field("stack", &self.inner.stack)
            .field("code", &self.inner.code)
            .finish()
    }
}
impl std::fmt::Display for JsErrorData {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            self.inner
                .message
                .clone()
                .unwrap_or_else(|| "N/A".to_string())
        )
    }
}
impl From<JsValue> for JsErrorData {
    fn from(error: JsValue) -> Self {
        let name = js_sys::Reflect::get(&error, &"name".into())
            .ok()
            .and_then(|v| v.as_string());
        let message = js_sys::Reflect::get(&error, &"message".into())
            .ok()
            .and_then(|v| v.as_string());
        let cause = js_sys::Reflect::get(&error, &"cause".into())
            .ok()
            .and_then(|v| v.as_string());
        let stack = js_sys::Reflect::get(&error, &"stack".into())
            .ok()
            .and_then(|v| v.as_string());
        let code = js_sys::Reflect::get(&error, &"code".into())
            .ok()
            .and_then(|v| v.as_string());
        Self {
            inner: Arc::new(Inner {
                name,
                message,
                cause,
                stack,
                code,
                origin: Sendable::new(error),
            }),
        }
    }
}
impl From<JsError> for JsErrorData {
    fn from(error: JsError) -> Self {
        JsValue::from(error).into()
    }
}
impl From<JsErrorData> for JsValue {
    fn from(error: JsErrorData) -> Self {
        error.inner.origin.as_ref().clone()
    }
}