//! The command / search bar shown at the bottom of the screen.
//!
//! Visible only in [`AppMode::Command`] and [`AppMode::Search`] modes.
//! Handles its own keyboard events (Enter, Escape) and stops propagation
//! so the global keymap does not also process those keys.

use leptos::prelude::*;
use web_sys::KeyboardEvent;

use crate::{commands::{self, CommandEffect}, mode::AppMode, ThemeContext};

/// Shared search query, provided in context so other components can read it.
///
/// Set by the search bar when the user commits a search (`<Enter>`).
/// Cleared when the user cancels with `<Esc>`.
#[derive(Clone, Copy)]
pub struct SearchQuery(pub RwSignal<String>);

pub fn provide_search_query() -> RwSignal<String> {
    let sig = RwSignal::new(String::new());
    provide_context(SearchQuery(sig));
    sig
}

/// The command/search bar component.
///
/// Pass the application mode signal; the bar appears/disappears reactively.
#[component]
pub fn CommandBar(mode: RwSignal<AppMode>) -> impl IntoView {
    let input_ref = NodeRef::<leptos::html::Input>::new();
    let (input_val, set_input_val) = signal(String::new());
    let (status_msg, set_status_msg) = signal(Option::<String>::None);

    let search_query = use_context::<SearchQuery>().map(|sq| sq.0);
    let theme = use_context::<ThemeContext>().map(|tc| tc.0);
    let reload_trigger = use_context::<crate::ReloadTrigger>().map(|r| r.0);

    // Clear input and status when the mode changes; autofocus on open.
    Effect::new(move |_| {
        let m = mode.get();
        set_input_val.set(String::new());
        set_status_msg.set(None);
        if m != AppMode::Normal {
            if let Some(el) = input_ref.get() {
                let _ = el.focus();
            }
        }
    });

    let prefix = move || match mode.get() {
        AppMode::Normal => "",
        AppMode::Command => ":",
        AppMode::Search => "/",
    };

    let on_keydown = move |ev: KeyboardEvent| {
        match ev.key().as_str() {
            "Escape" => {
                ev.prevent_default();
                ev.stop_propagation();
                // Cancel: clear search query and return to normal.
                if let Some(sq) = search_query {
                    sq.set(String::new());
                }
                mode.set(AppMode::Normal);
            }
            "Enter" => {
                ev.prevent_default();
                ev.stop_propagation();
                let val = input_val.get_untracked();
                match mode.get_untracked() {
                    AppMode::Command => {
                        let outcome = commands::dispatch(&val);
                        if let Some(msg) = outcome.message {
                            // Show error; stay in command mode.
                            set_status_msg.set(Some(msg));
                            return;
                        }
                        if let Some(effect) = outcome.effect {
                            match effect {
                                CommandEffect::SetTheme(t) => {
                                    if let Some(sig) = theme {
                                        sig.set(t.clone());
                                    }
                                    leptos::task::spawn_local(async move {
                                        let _ = crate::tauri::set_theme(&t).await;
                                    });
                                }
                                CommandEffect::OpenRepository(path) => {
                                    let reload = reload_trigger;
                                    leptos::task::spawn_local(async move {
                                        match crate::tauri::open_repository(&path).await {
                                            Ok(()) => {
                                                if let Some(t) = reload {
                                                    t.update(|n| *n += 1);
                                                }
                                                mode.set(AppMode::Normal);
                                            }
                                            Err(e) => set_status_msg.set(Some(e)),
                                        }
                                    });
                                    return; // stay open until async resolves
                                }
                            }
                        }
                        mode.set(AppMode::Normal);
                    }
                    AppMode::Search => {
                        // Commit the search query and return to normal.
                        if let Some(sq) = search_query {
                            sq.set(val);
                        }
                        mode.set(AppMode::Normal);
                    }
                    AppMode::Normal => {}
                }
            }
            _ => {}
        }
    };

    let on_input = move |ev: web_sys::Event| {
        set_input_val.set(event_target_value(&ev));
        set_status_msg.set(None);
    };

    view! {
        <Show when=move || mode.get() != AppMode::Normal>
            <div class="command-bar">
                <span class="command-prefix">{prefix}</span>
                <input
                    node_ref=input_ref
                    type="text"
                    class="command-input"
                    prop:value=input_val
                    on:input=on_input
                    on:keydown=on_keydown
                    autocomplete="off"
                    spellcheck="false"
                />
                {move || status_msg.get().map(|m| view! {
                    <span class="command-status">" — "{m}</span>
                })}
            </div>
        </Show>
    }
}
