//! WASM-specific utilities (enabled with "wasm" feature)

#[cfg(target_arch = "wasm32")]
use wasm_bindgen::prelude::*;

#[cfg(target_arch = "wasm32")]
use web_sys::{console, window, Window, Document, HtmlElement};

/// Console logging utilities for WASM
pub mod console {
    #[cfg(target_arch = "wasm32")]
    use super::*;

    /// Log message to browser console
    #[cfg(target_arch = "wasm32")]
    pub fn log(message: &str) {
        console::log_1(&message.into());
    }

    /// Log error to browser console
    #[cfg(target_arch = "wasm32")]
    pub fn error(message: &str) {
        console::error_1(&message.into());
    }

    /// Log warning to browser console
    #[cfg(target_arch = "wasm32")]
    pub fn warn(message: &str) {
        console::warn_1(&message.into());
    }

    /// No-op implementations for non-WASM targets
    #[cfg(not(target_arch = "wasm32"))]
    pub fn log(_message: &str) {}

    #[cfg(not(target_arch = "wasm32"))]
    pub fn error(_message: &str) {}

    #[cfg(not(target_arch = "wasm32"))]
    pub fn warn(_message: &str) {}
}

/// DOM manipulation utilities for WASM
pub mod dom {
    #[cfg(target_arch = "wasm32")]
    use super::*;

    /// Get the window object
    #[cfg(target_arch = "wasm32")]
    pub fn window() -> Result<Window, JsValue> {
        web_sys::window().ok_or_else(|| JsValue::from_str("No window object"))
    }

    /// Get the document object
    #[cfg(target_arch = "wasm32")]
    pub fn document() -> Result<Document, JsValue> {
        window()?
            .document()
            .ok_or_else(|| JsValue::from_str("No document object"))
    }

    /// Get element by ID
    #[cfg(target_arch = "wasm32")]
    pub fn get_element_by_id(id: &str) -> Result<Option<HtmlElement>, JsValue> {
        let doc = document()?;
        Ok(doc
            .get_element_by_id(id)
            .and_then(|elem| elem.dyn_into::<HtmlElement>().ok()))
    }

    /// Set element text content
    #[cfg(target_arch = "wasm32")]
    pub fn set_text_content(element: &HtmlElement, content: &str) {
        element.set_text_content(Some(content));
    }

    /// Set element inner HTML
    #[cfg(target_arch = "wasm32")]
    pub fn set_inner_html(element: &HtmlElement, html: &str) {
        element.set_inner_html(html);
    }

    /// No-op implementations for non-WASM targets
    #[cfg(not(target_arch = "wasm32"))]
    pub fn window() -> Result<(), &'static str> {
        Err("Not available on non-WASM targets")
    }

    #[cfg(not(target_arch = "wasm32"))]
    pub fn document() -> Result<(), &'static str> {
        Err("Not available on non-WASM targets")
    }
}

/// Local storage utilities for WASM
pub mod storage {
    #[cfg(target_arch = "wasm32")]
    use super::*;

    /// Get item from local storage
    #[cfg(target_arch = "wasm32")]
    pub fn get_item(key: &str) -> Result<Option<String>, JsValue> {
        let storage = window()?
            .local_storage()?
            .ok_or_else(|| JsValue::from_str("No localStorage"))?;

        storage.get_item(key)
    }

    /// Set item in local storage
    #[cfg(target_arch = "wasm32")]
    pub fn set_item(key: &str, value: &str) -> Result<(), JsValue> {
        let storage = window()?
            .local_storage()?
            .ok_or_else(|| JsValue::from_str("No localStorage"))?;

        storage.set_item(key, value)
    }

    /// Remove item from local storage
    #[cfg(target_arch = "wasm32")]
    pub fn remove_item(key: &str) -> Result<(), JsValue> {
        let storage = window()?
            .local_storage()?
            .ok_or_else(|| JsValue::from_str("No localStorage"))?;

        storage.remove_item(key)
    }

    /// No-op implementations for non-WASM targets
    #[cfg(not(target_arch = "wasm32"))]
    pub fn get_item(_key: &str) -> Result<Option<String>, &'static str> {
        Err("Not available on non-WASM targets")
    }

    #[cfg(not(target_arch = "wasm32"))]
    pub fn set_item(_key: &str, _value: &str) -> Result<(), &'static str> {
        Err("Not available on non-WASM targets")
    }

    #[cfg(not(target_arch = "wasm32"))]
    pub fn remove_item(_key: &str) -> Result<(), &'static str> {
        Err("Not available on non-WASM targets")
    }
}

/// HTTP utilities for WASM
pub mod http {
    #[cfg(target_arch = "wasm32")]
    use super::*;

    #[cfg(target_arch = "wasm32")]
    use reqwasm::http::Request;

    /// Simple GET request
    #[cfg(target_arch = "wasm32")]
    pub async fn get(url: &str) -> Result<String, reqwasm::Error> {
        let response = Request::get(url).send().await?;
        response.text().await
    }

    /// Simple POST request with JSON body
    #[cfg(target_arch = "wasm32")]
    pub async fn post_json(url: &str, body: &str) -> Result<String, reqwasm::Error> {
        let response = Request::post(url)
            .header("Content-Type", "application/json")
            .body(body)
            .send()
            .await?;
        response.text().await
    }

    /// No-op implementations for non-WASM targets
    #[cfg(not(target_arch = "wasm32"))]
    pub async fn get(_url: &str) -> Result<String, &'static str> {
        Err("Not available on non-WASM targets")
    }

    #[cfg(not(target_arch = "wasm32"))]
    pub async fn post_json(_url: &str, _body: &str) -> Result<String, &'static str> {
        Err("Not available on non-WASM targets")
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_console_logging() {
        // These are no-ops on non-WASM, but should not panic
        console::log("Test message");
        console::error("Test error");
        console::warn("Test warning");
    }

    #[test]
    fn test_dom_functions() {
        // These should return errors on non-WASM targets
        let result = dom::window();
        assert!(result.is_err());

        let result = dom::document();
        assert!(result.is_err());
    }

    #[test]
    fn test_storage_functions() {
        // These should return errors on non-WASM targets
        let result = storage::get_item("test");
        assert!(result.is_err());

        let result = storage::set_item("test", "value");
        assert!(result.is_err());

        let result = storage::remove_item("test");
        assert!(result.is_err());
    }

    #[tokio::test]
    async fn test_http_functions() {
        // These should return errors on non-WASM targets
        let result = http::get("https://example.com").await;
        assert!(result.is_err());

        let result = http::post_json("https://example.com", "{}").await;
        assert!(result.is_err());
    }
}
