//! Notification components for whispers and system messages.
//!
//! Provides toast notifications for cross-scene whispers with keybindings.

use leptos::prelude::*;
use uuid::Uuid;
#[cfg(feature = "hydrate")]
use wasm_bindgen::JsCast;

use super::chat_types::ChatMessage;

/// A notification message for display.
#[derive(Debug, Clone, PartialEq)]
pub struct NotificationMessage {
    pub id: Uuid,
    pub chat_message: ChatMessage,
    /// When the notification was created (milliseconds since epoch).
    pub created_at: i64,
    /// Whether the notification has been dismissed.
    pub dismissed: bool,
}

impl NotificationMessage {
    /// Create a new notification from a chat message.
    #[cfg(feature = "hydrate")]
    pub fn from_chat_message(msg: ChatMessage) -> Self {
        Self {
            id: Uuid::new_v4(),
            chat_message: msg,
            created_at: js_sys::Date::now() as i64,
            dismissed: false,
        }
    }

    /// SSR stub.
    #[cfg(not(feature = "hydrate"))]
    pub fn from_chat_message(msg: ChatMessage) -> Self {
        Self {
            id: Uuid::new_v4(),
            chat_message: msg,
            created_at: 0,
            dismissed: false,
        }
    }
}

/// Toast notification component for cross-scene whispers.
///
/// Displays in the top-right corner with auto-dismiss and keybindings.
#[component]
pub fn NotificationToast(
    /// The notification to display.
    #[prop(into)]
    notification: Signal<Option<NotificationMessage>>,
    /// Callback when user wants to reply (press 'r').
    on_reply: Callback<String>,
    /// Callback when user wants to see context (press 'c').
    on_context: Callback<String>,
    /// Callback when notification is dismissed.
    on_dismiss: Callback<Uuid>,
) -> impl IntoView {
    // Auto-dismiss timer
    #[cfg(feature = "hydrate")]
    {
        use std::cell::RefCell;
        use std::rc::Rc;

        let timer_handle = Rc::new(RefCell::new(None::<i32>));
        let timer_handle_effect = timer_handle.clone();

        Effect::new(move |_| {
            let notif = notification.get();

            // Clear any existing timer
            if let Some(handle) = timer_handle_effect.borrow_mut().take() {
                web_sys::window().unwrap().clear_timeout_with_handle(handle);
            }

            // Start new timer if notification is present
            if let Some(ref n) = notif {
                let id = n.id;
                let on_dismiss = on_dismiss.clone();
                let timer_handle_inner = timer_handle_effect.clone();

                let closure = wasm_bindgen::closure::Closure::once(Box::new(move || {
                    on_dismiss.run(id);
                    timer_handle_inner.borrow_mut().take();
                })
                    as Box<dyn FnOnce()>);

                if let Some(window) = web_sys::window() {
                    if let Ok(handle) = window
                        .set_timeout_with_callback_and_timeout_and_arguments_0(
                            closure.as_ref().unchecked_ref(),
                            5000, // 5 second auto-dismiss
                        )
                    {
                        *timer_handle_effect.borrow_mut() = Some(handle);
                    }
                }
                closure.forget();
            }
        });
    }

    // Keybinding handler with proper cleanup
    #[cfg(feature = "hydrate")]
    {
        use std::cell::RefCell;
        use std::rc::Rc;

        let closure_holder: Rc<
            RefCell<Option<wasm_bindgen::closure::Closure<dyn Fn(web_sys::KeyboardEvent)>>>,
        > = Rc::new(RefCell::new(None));
        let closure_holder_clone = closure_holder.clone();

        Effect::new(move |_| {
            let notif = notification.get();

            // Cleanup previous listener
            if let Some(old_closure) = closure_holder_clone.borrow_mut().take() {
                if let Some(window) = web_sys::window() {
                    let _ = window.remove_event_listener_with_callback(
                        "keydown",
                        old_closure.as_ref().unchecked_ref(),
                    );
                }
            }

            // Only add listener if notification is present
            let Some(ref n) = notif else {
                return;
            };

            let display_name = n.chat_message.display_name.clone();
            let notif_id = n.id;

            let on_reply = on_reply.clone();
            let on_context = on_context.clone();
            let on_dismiss = on_dismiss.clone();

            let closure = wasm_bindgen::closure::Closure::<dyn Fn(web_sys::KeyboardEvent)>::new(
                move |ev: web_sys::KeyboardEvent| {
                    let key = ev.key();
                    match key.as_str() {
                        "r" | "R" => {
                            ev.prevent_default();
                            on_reply.run(display_name.clone());
                            on_dismiss.run(notif_id);
                        }
                        "c" | "C" => {
                            ev.prevent_default();
                            on_context.run(display_name.clone());
                            on_dismiss.run(notif_id);
                        }
                        "Escape" => {
                            ev.prevent_default();
                            on_dismiss.run(notif_id);
                        }
                        _ => {}
                    }
                },
            );

            if let Some(window) = web_sys::window() {
                let _ = window
                    .add_event_listener_with_callback("keydown", closure.as_ref().unchecked_ref());
            }

            // Store closure for cleanup on next change
            *closure_holder_clone.borrow_mut() = Some(closure);
        });
    }

    view! {
        <Show when=move || notification.get().is_some()>
            {move || {
                let notif = notification.get();
                if let Some(n) = notif {
                    let content_preview = if n.chat_message.content.len() > 50 {
                        format!("\"{}...\"", &n.chat_message.content[..47])
                    } else {
                        format!("\"{}\"", n.chat_message.content)
                    };

                    view! {
                        <div class="fixed top-4 right-4 z-50 max-w-sm w-full animate-slide-in-right">
                            <div class="bg-gray-800 border border-purple-500/50 rounded-lg shadow-lg p-4">
                                // Header
                                <div class="flex items-center gap-2 mb-2">
                                    <span class="text-lg">"💬"</span>
                                    <span class="text-purple-300 font-medium">
                                        {n.chat_message.display_name.clone()} " whispered to you"
                                    </span>
                                </div>

                                // Content
                                <p class="text-gray-300 italic mb-3">
                                    {content_preview}
                                </p>

                                // Keybinding hints
                                <div class="flex gap-3 text-xs text-gray-500">
                                    <span>
                                        <kbd class="px-1.5 py-0.5 bg-gray-700 rounded text-gray-400">"r"</kbd>
                                        " reply"
                                    </span>
                                    <span>
                                        <kbd class="px-1.5 py-0.5 bg-gray-700 rounded text-gray-400">"c"</kbd>
                                        " context"
                                    </span>
                                </div>
                            </div>
                        </div>
                    }.into_any()
                } else {
                    ().into_any()
                }
            }}
        </Show>
    }
}
