//! Message log popup component.
//!
//! Displays a filterable chronological log of received messages.
//! Includes persistent whisper history via LocalStorage.

use leptos::prelude::*;
use leptos::reactive::owner::LocalStorage;

use super::chat_types::{ChatMessage, MessageLog};
use super::modals::Modal;

/// LocalStorage key for persistent whisper history.
const WHISPER_STORAGE_KEY: &str = "chattyness_whisper_history";
/// Maximum number of whispers to keep in persistent history.
const MAX_WHISPER_HISTORY: usize = 100;

/// Load whisper history from LocalStorage.
#[cfg(feature = "hydrate")]
pub fn load_whisper_history() -> Vec<ChatMessage> {
    let window = match web_sys::window() {
        Some(w) => w,
        None => return Vec::new(),
    };

    let storage = match window.local_storage() {
        Ok(Some(s)) => s,
        _ => return Vec::new(),
    };

    let json = match storage.get_item(WHISPER_STORAGE_KEY) {
        Ok(Some(j)) => j,
        _ => return Vec::new(),
    };

    serde_json::from_str(&json).unwrap_or_default()
}

/// Save whisper history to LocalStorage.
#[cfg(feature = "hydrate")]
pub fn save_whisper_history(whispers: &[ChatMessage]) {
    let window = match web_sys::window() {
        Some(w) => w,
        None => return,
    };

    let storage = match window.local_storage() {
        Ok(Some(s)) => s,
        _ => return,
    };

    if let Ok(json) = serde_json::to_string(whispers) {
        let _ = storage.set_item(WHISPER_STORAGE_KEY, &json);
    }
}

/// Add a whisper to persistent history, maintaining max size.
/// Deduplicates by message_id.
#[cfg(feature = "hydrate")]
pub fn add_whisper_to_history(msg: ChatMessage) {
    let mut history = load_whisper_history();
    // Avoid duplicates by message_id
    if !history.iter().any(|m| m.message_id == msg.message_id) {
        history.insert(0, msg);
        if history.len() > MAX_WHISPER_HISTORY {
            history.truncate(MAX_WHISPER_HISTORY);
        }
        save_whisper_history(&history);
    }
}

/// SSR stubs for persistence functions.
#[cfg(not(feature = "hydrate"))]
pub fn load_whisper_history() -> Vec<ChatMessage> {
    Vec::new()
}

#[cfg(not(feature = "hydrate"))]
pub fn save_whisper_history(_whispers: &[ChatMessage]) {}

#[cfg(not(feature = "hydrate"))]
pub fn add_whisper_to_history(_msg: ChatMessage) {}

/// Filter mode for message log display.
#[derive(Clone, Copy, PartialEq, Eq, Default)]
pub enum LogFilter {
    /// Show all messages.
    #[default]
    All,
    /// Show only broadcast chat messages.
    Chat,
    /// Show only whispers.
    Whispers,
    /// Show only system/admin messages (teleports, summons, mod commands).
    System,
}

/// Message log popup component.
///
/// Displays a filterable list of messages from the session,
/// with persistent whisper history from LocalStorage.
#[component]
pub fn LogPopup(
    #[prop(into)] open: Signal<bool>,
    message_log: StoredValue<MessageLog, LocalStorage>,
    on_close: Callback<()>,
    /// Callback when user wants to reply to a whisper.
    on_reply: Callback<String>,
    /// Callback when user wants to see conversation context.
    on_context: Callback<String>,
) -> impl IntoView {
    let (filter, set_filter) = signal(LogFilter::All);

    // Get filtered messages based on current filter
    // Note: We read `open` to force re-evaluation when the modal opens,
    // since StoredValue is not reactive.
    let filtered_messages = move || {
        // Reading open ensures we re-fetch messages when modal opens
        let _ = open.get();
        let current_filter = filter.get();

        match current_filter {
            LogFilter::Whispers => {
                // For whispers, merge session messages with persistent history
                let mut session_whispers: Vec<ChatMessage> = message_log.with_value(|log| {
                    log.all_messages()
                        .iter()
                        .filter(|msg| msg.is_whisper)
                        .cloned()
                        .collect()
                });

                // Load persistent whispers and merge (avoiding duplicates by message_id)
                let persistent = load_whisper_history();
                for msg in persistent {
                    if !session_whispers.iter().any(|m| m.message_id == msg.message_id) {
                        session_whispers.push(msg);
                    }
                }

                // Sort by timestamp (oldest first for display)
                session_whispers.sort_by_key(|m| m.timestamp);
                session_whispers
            }
            _ => {
                // For All, Chat, or System, use session messages only
                message_log.with_value(|log| {
                    log.all_messages()
                        .iter()
                        .filter(|msg| match current_filter {
                            LogFilter::All => true,
                            LogFilter::Chat => !msg.is_whisper && !msg.is_system,
                            LogFilter::System => msg.is_system,
                            LogFilter::Whispers => unreachable!(),
                        })
                        .cloned()
                        .collect::<Vec<_>>()
                })
            }
        }
    };

    // Auto-scroll to bottom when modal opens
    #[cfg(feature = "hydrate")]
    {
        Effect::new(move |_| {
            if open.get() {
                // Use a small delay to ensure the DOM is rendered
                use gloo_timers::callback::Timeout;
                Timeout::new(50, || {
                    if let Some(document) = web_sys::window().and_then(|w| w.document()) {
                        if let Some(container) = document
                            .query_selector(".log-popup-messages")
                            .ok()
                            .flatten()
                        {
                            let scroll_height = container.scroll_height();
                            container.set_scroll_top(scroll_height);
                        }
                    }
                })
                .forget();
            }
        });
    }

    let tab_class = |is_active: bool| {
        if is_active {
            "px-3 py-1.5 rounded text-sm font-medium bg-blue-600 text-white"
        } else {
            "px-3 py-1.5 rounded text-sm font-medium bg-gray-700 text-gray-300 hover:bg-gray-600"
        }
    };

    view! {
        <Modal
            open=open
            on_close=on_close.clone()
            title="Message Log"
            title_id="message-log-title"
            max_width="max-w-2xl"
        >
            // Filter tabs
            <div class="flex gap-2 mb-4">
                <button
                    class=move || tab_class(filter.get() == LogFilter::All)
                    on:click=move |_| set_filter.set(LogFilter::All)
                >
                    "All"
                </button>
                <button
                    class=move || tab_class(filter.get() == LogFilter::Chat)
                    on:click=move |_| set_filter.set(LogFilter::Chat)
                >
                    "Chat"
                </button>
                <button
                    class=move || tab_class(filter.get() == LogFilter::Whispers)
                    on:click=move |_| set_filter.set(LogFilter::Whispers)
                >
                    "Whispers"
                </button>
                <button
                    class=move || tab_class(filter.get() == LogFilter::System)
                    on:click=move |_| set_filter.set(LogFilter::System)
                >
                    "System"
                </button>
            </div>

            // Message list
            <div class="log-popup-messages max-h-[70vh] overflow-y-auto bg-gray-900/50 rounded-lg p-2">
                <Show
                    when=move || !filtered_messages().is_empty()
                    fallback=|| view! {
                        <p class="text-gray-400 text-center py-8">
                            "No messages yet"
                        </p>
                    }
                >
                    <ul class="space-y-1 font-mono text-sm">
                        <For
                            each=move || filtered_messages()
                            key=|msg| msg.message_id
                            children={
                                let on_reply = on_reply.clone();
                                let on_context = on_context.clone();
                                let on_close = on_close.clone();
                                move |msg: ChatMessage| {
                                    let is_whisper = msg.is_whisper;
                                    let is_system = msg.is_system;
                                    let display_name = msg.display_name.clone();
                                    let display_name_for_reply = display_name.clone();
                                    let display_name_for_context = display_name.clone();
                                    let content = msg.content.clone();
                                    let timestamp = msg.timestamp;

                                    let on_reply = on_reply.clone();
                                    let on_context = on_context.clone();
                                    let on_close = on_close.clone();
                                    let on_close2 = on_close.clone();

                                    view! {
                                        <li class=move || {
                                            if is_system {
                                                "py-1 px-2 rounded bg-yellow-900/30 border-l-2 border-yellow-500"
                                            } else if is_whisper {
                                                "py-1 px-2 rounded bg-purple-900/30 border-l-2 border-purple-500"
                                            } else {
                                                "py-1 px-2"
                                            }
                                        }>
                                            <div class="flex items-start justify-between">
                                                <div class="flex-1">
                                                    <span class="text-gray-500">
                                                        "["
                                                        {format_timestamp(timestamp)}
                                                        "] "
                                                    </span>
                                                    <span class=move || {
                                                        if is_system {
                                                            "text-yellow-300 font-medium"
                                                        } else if is_whisper {
                                                            "text-purple-300 font-medium"
                                                        } else {
                                                            "text-blue-300 font-medium"
                                                        }
                                                    }>
                                                        {display_name}
                                                    </span>
                                                    <Show when=move || is_system>
                                                        <span class="text-yellow-400 text-xs ml-1">
                                                            "(system)"
                                                        </span>
                                                    </Show>
                                                    <Show when=move || is_whisper && !is_system>
                                                        <span class="text-purple-400 text-xs ml-1">
                                                            "(whisper)"
                                                        </span>
                                                    </Show>
                                                    <span class="text-gray-400">
                                                        ": "
                                                    </span>
                                                    <span class=move || {
                                                        if is_system {
                                                            "text-yellow-200"
                                                        } else if is_whisper {
                                                            "text-gray-300 italic"
                                                        } else {
                                                            "text-gray-200"
                                                        }
                                                    }>
                                                        {content}
                                                    </span>
                                                </div>
                                                <Show when=move || is_whisper && !is_system>
                                                    <div class="flex gap-1 ml-2 flex-shrink-0">
                                                        <button
                                                            class="px-2 py-0.5 text-xs bg-gray-600 hover:bg-gray-500 rounded text-gray-300"
                                                            title="Reply"
                                                            on:click={
                                                                let on_reply = on_reply.clone();
                                                                let sender = display_name_for_reply.clone();
                                                                let on_close = on_close.clone();
                                                                move |_| {
                                                                    on_reply.run(sender.clone());
                                                                    on_close.run(());
                                                                }
                                                            }
                                                        >
                                                            "Reply"
                                                        </button>
                                                        <button
                                                            class="px-2 py-0.5 text-xs bg-gray-600 hover:bg-gray-500 rounded text-gray-300"
                                                            title="View conversation"
                                                            on:click={
                                                                let on_context = on_context.clone();
                                                                let sender = display_name_for_context.clone();
                                                                let on_close = on_close2.clone();
                                                                move |_| {
                                                                    on_context.run(sender.clone());
                                                                    on_close.run(());
                                                                }
                                                            }
                                                        >
                                                            "Context"
                                                        </button>
                                                    </div>
                                                </Show>
                                            </div>
                                        </li>
                                    }
                                }
                            }
                        />
                    </ul>
                </Show>
            </div>

            // Footer hint
            <div class="mt-4 pt-4 border-t border-gray-600 text-xs text-gray-500 text-center">
                "Press " <kbd class="px-1.5 py-0.5 bg-gray-700 rounded">"Esc"</kbd> " to close"
            </div>
        </Modal>
    }
}

/// Format a timestamp for display (HH:MM:SS).
fn format_timestamp(timestamp: i64) -> String {
    #[cfg(feature = "hydrate")]
    {
        let date = js_sys::Date::new(&wasm_bindgen::JsValue::from_f64(timestamp as f64));
        let hours = date.get_hours();
        let minutes = date.get_minutes();
        let seconds = date.get_seconds();
        format!("{:02}:{:02}:{:02}", hours, minutes, seconds)
    }
    #[cfg(not(feature = "hydrate"))]
    {
        let _ = timestamp;
        String::new()
    }
}
