use std::sync::atomic::{AtomicU64, Ordering};
#[cfg(target_arch = "wasm32")]
use std::{cell::Cell, time::Duration};

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

pub mod unified;
pub use unified::ToastContainer;

// ── Types ────────────────────────────────────────────────────────────────────

#[derive(Clone, Debug, PartialEq)]
pub enum ToastKind {
    Info,
    Warning,
    Error,
}

#[derive(Clone, Debug)]
pub struct ToastNotification {
    pub id: u64,
    pub kind: ToastKind,
    pub message: String,
}

// ── Context helpers ──────────────────────────────────────────────────────────

pub fn provide_toast_context() {
    provide_context(RwSignal::<Vec<ToastNotification>>::new(vec![]));
}

pub fn push_toast_to(sig: RwSignal<Vec<ToastNotification>>, kind: ToastKind, message: &str) {
    let id = next_id();
    sig.update(|v| {
        v.push(ToastNotification {
            id,
            kind,
            message: message.to_string(),
        })
    });

    #[cfg(target_arch = "wasm32")]
    set_timeout(
        move || sig.update(|v| v.retain(|t| t.id != id)),
        Duration::from_millis(5_000),
    );
}

pub fn push_toast(kind: ToastKind, message: &str) {
    if let Some(sig) = use_context::<RwSignal<Vec<ToastNotification>>>() {
        push_toast_to(sig, kind, message);
    }
}

pub(super) fn next_id() -> u64 {
    static COUNTER: AtomicU64 = AtomicU64::new(1);
    COUNTER.fetch_add(1, Ordering::Relaxed)
}

// ── WASM global signal store ─────────────────────────────────────────────────
//
// Module-level thread_local so both `register_toast_signal` and
// `push_toast_from_js` share the same storage cell.

#[cfg(target_arch = "wasm32")]
thread_local! {
    static TOAST_SIGNAL: Cell<Option<RwSignal<Vec<ToastNotification>>>> = Cell::new(None);
}

/// Store the app's toast signal so it's reachable outside any reactive context.
/// Call once from `app.rs` after `toast_sig` is created.
#[cfg(target_arch = "wasm32")]
pub fn register_toast_signal(sig: RwSignal<Vec<ToastNotification>>) {
    TOAST_SIGNAL.with(|s| s.set(Some(sig)));
}

/// JS-accessible export: `rustelo_push_toast("info"|"warning"|"error",
/// "message")` Available in the browser console after WASM initialises.
#[cfg(target_arch = "wasm32")]
#[wasm_bindgen(js_name = "rustelo_push_toast")]
pub fn push_toast_from_js(kind: &str, message: &str) {
    let k = match kind {
        "error" => ToastKind::Error,
        "warning" => ToastKind::Warning,
        _ => ToastKind::Info,
    };
    TOAST_SIGNAL.with(|s| {
        if let Some(sig) = s.get() {
            push_toast_to(sig, k, message);
        }
    });
}
