use std::collections::VecDeque;

use leptos::prelude::*;

/// Toast message type
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum ToastType {
    Success,
    Error,
    Warning,
    Info,
}

impl ToastType {
    /// Get CSS classes for toast type
    pub fn classes(&self) -> &'static str {
        match self {
            Self::Success => "bg-green-500/90 border-green-400/70",
            Self::Error => "bg-red-500/90 border-red-400/70",
            Self::Warning => "bg-yellow-500/90 border-yellow-400/70",
            Self::Info => "bg-blue-500/90 border-blue-400/70",
        }
    }
}

/// Toast message data
#[derive(Clone, Debug)]
pub struct ToastMessage {
    pub id: String,
    pub message: String,
    pub toast_type: ToastType,
}

/// Toast context for managing toast notifications
#[derive(Clone, Copy)]
pub struct ToastContext {
    toasts: RwSignal<VecDeque<ToastMessage>>,
}

impl ToastContext {
    /// Create a new toast context
    pub fn new() -> Self {
        Self {
            toasts: RwSignal::new(VecDeque::new()),
        }
    }

    /// Show a toast notification
    pub fn show_toast(&self, message: String, toast_type: ToastType) {
        let id = uuid::Uuid::new_v4().to_string();
        let toast = ToastMessage {
            id: id.clone(),
            message,
            toast_type,
        };

        self.toasts.update(|t| t.push_back(toast));

        // Auto-dismiss after 3 seconds
        #[cfg(target_arch = "wasm32")]
        {
            let toasts_clone = self.toasts;
            wasm_bindgen_futures::spawn_local(async move {
                gloo_timers::future::TimeoutFuture::new(3000).await;
                toasts_clone.update(|t| t.retain(|msg| msg.id != id));
            });
        }
    }

    /// Show success toast
    pub fn success(&self, message: String) {
        self.show_toast(message, ToastType::Success);
    }

    /// Show error toast
    pub fn error(&self, message: String) {
        self.show_toast(message, ToastType::Error);
    }

    /// Show warning toast
    pub fn warning(&self, message: String) {
        self.show_toast(message, ToastType::Warning);
    }

    /// Show info toast
    pub fn info(&self, message: String) {
        self.show_toast(message, ToastType::Info);
    }

    /// Get all toasts
    pub fn toasts(&self) -> Signal<VecDeque<ToastMessage>> {
        self.toasts.into()
    }

    /// Dismiss a toast by ID
    pub fn dismiss(&self, id: &str) {
        self.toasts.update(|t| t.retain(|msg| msg.id != id));
    }
}

impl Default for ToastContext {
    fn default() -> Self {
        Self::new()
    }
}

/// Hook to access toast context
///
/// # Panics
///
/// Panics if called outside of a `ToastProvider`
pub fn use_toast() -> ToastContext {
    use_context::<ToastContext>().expect("use_toast must be called within a ToastProvider")
}

/// Helper function to render toast messages
fn render_toasts(toasts: VecDeque<ToastMessage>, context: ToastContext) -> Vec<impl IntoView> {
    toasts
        .into_iter()
        .map(|toast| {
            let toast_id = toast.id.clone();
            let context_for_dismiss = context;

            view! {
                <div
                    class={format!(
                        "pointer-events-auto px-4 py-3 rounded-lg shadow-lg backdrop-blur-md \
                         border text-white font-medium transition-all duration-300 \
                         {}",
                        toast.toast_type.classes()
                    )}
                >
                    <div class="flex items-center gap-2">
                        <span>{toast.message.clone()}</span>
                        <button
                            class="ml-2 text-white/80 hover:text-white"
                            on:click=move |_| {
                                context_for_dismiss.dismiss(&toast_id);
                            }
                        >
                            "×"
                        </button>
                    </div>
                </div>
            }
        })
        .collect()
}

/// Toast provider component
///
/// Wraps your app to provide toast notifications.
///
/// # Example
///
/// ```rust
/// use leptos::prelude::*;
/// use vapora_leptos_ui::{ToastProvider, use_toast};
///
/// #[component]
/// fn App() -> impl IntoView {
///     view! {
///         <ToastProvider>
///             <MyApp />
///         </ToastProvider>
///     }
/// }
///
/// #[component]
/// fn MyApp() -> impl IntoView {
///     let toast = use_toast();
///
///     view! {
///         <button on:click=move |_| {
///             toast.success("Operation successful!".to_string());
///         }>"Show Toast"</button>
///     }
/// }
/// ```
#[component]
pub fn ToastProvider(children: Children) -> impl IntoView {
    let context = ToastContext::new();
    let toasts = context.toasts();

    provide_context(context);

    view! {
        {children()}

        // Toast container
        <div class="fixed top-4 right-4 z-50 flex flex-col gap-2 pointer-events-none">
            {move || render_toasts(toasts.get(), context)}
        </div>
    }
}
