use leptos::prelude::*;
use leptos::task::spawn_local;

use crate::auth::server_fns::{server_add_bookmark, server_get_bookmarks, server_remove_bookmark};

/// Interactive bookmark toggle button for a content item.
///
/// Renders a star icon that reflects whether the current authenticated user
/// has bookmarked the given content.  On SSR and before the async state load
/// completes, the button is rendered disabled (neutral "loading" state) so
/// both SSR and WASM produce identical initial HTML — no hydration mismatch.
///
/// - **Loading / unauthenticated** (`None`): disabled button; click redirects
///   to login.
/// - **Not bookmarked** (`Some(false)`): outline star; click adds bookmark.
/// - **Bookmarked** (`Some(true)`): filled star; click removes bookmark.
#[component]
pub fn BookmarkButton(
    content_id: String,
    content_type: String,
    content_title: String,
    content_url: String,
) -> impl IntoView {
    // None = loading / unauthenticated; Some(bool) = resolved bookmarked state.
    // Both SSR and WASM start with None → identical initial render.
    let bookmarked: RwSignal<Option<bool>> = RwSignal::new(None);

    // Load state on WASM only — SSR renders the disabled "loading" state.
    // All WASM-specific bindings (server_is_bookmarked, set_path) are scoped
    // here to avoid unused-import/variable warnings on non-WASM builds.
    #[cfg(target_arch = "wasm32")]
    let set_path = use_context::<WriteSignal<String>>();

    #[cfg(target_arch = "wasm32")]
    {
        use crate::auth::server_fns::server_is_bookmarked;

        let cid = content_id.clone();
        let ctype = content_type.clone();
        let bm = bookmarked;
        spawn_local(async move {
            // Treat any error (including unauthenticated) as "not bookmarked".
            let state = server_is_bookmarked(cid, ctype).await.unwrap_or(false);
            bm.set(Some(state));
        });
    }

    // Capture props for the click handler.  Strings are moved into the closure;
    // inner async blocks clone them as needed so the closure remains FnMut.
    let cid2 = content_id.clone();
    let ctype2 = content_type.clone();
    let ctitle2 = content_title.clone();
    let curl2 = content_url.clone();

    let on_click = move |_| {
        let state = bookmarked.get_untracked();
        let bm = bookmarked;

        match state {
            None => {
                // State not yet loaded → send to login so user can authenticate.
                #[cfg(target_arch = "wasm32")]
                if let Some(setter) = set_path {
                    let current = web_sys::window()
                        .and_then(|w| w.location().pathname().ok())
                        .unwrap_or_default();
                    setter.set(format!("/login?return={}", current));
                }
            }
            Some(false) => {
                let ct = ctype2.clone();
                let cid = cid2.clone();
                let title = ctitle2.clone();
                let url = curl2.clone();
                spawn_local(async move {
                    match server_add_bookmark(ct, cid, Some(title), Some(url)).await {
                        Ok(_) => bm.set(Some(true)),
                        Err(_) => {
                            // Auth failure or transient error — redirect to login.
                            #[cfg(target_arch = "wasm32")]
                            if let Some(setter) = set_path {
                                let current = web_sys::window()
                                    .and_then(|w| w.location().pathname().ok())
                                    .unwrap_or_default();
                                setter.set(format!("/login?return={}", current));
                            }
                        }
                    }
                });
            }
            Some(true) => {
                let ct = ctype2.clone();
                let cid = cid2.clone();
                spawn_local(async move {
                    // Fetch bookmark list to retrieve the UUID needed for removal.
                    if let Ok(bookmarks) = server_get_bookmarks().await {
                        if let Some(entry) = bookmarks
                            .iter()
                            .find(|b| b.content_id == cid && b.content_type == ct)
                        {
                            let uuid = entry.id.clone();
                            if server_remove_bookmark(uuid).await.is_ok() {
                                bm.set(Some(false));
                            }
                        }
                    }
                });
            }
        }
    };

    view! {
        <button
            class=move || {
                let base = "btn btn-ghost btn-sm";
                match bookmarked.get() {
                    Some(true) => format!("{} text-warning", base),
                    _ => base.to_string(),
                }
            }
            disabled=move || bookmarked.get().is_none()
            on:click=on_click
            title=move || match bookmarked.get() {
                Some(true) => "Remove bookmark",
                Some(false) => "Add bookmark",
                None => "Loading…",
            }
            aria-label=move || match bookmarked.get() {
                Some(true) => "Remove bookmark",
                Some(false) => "Add bookmark",
                None => "Loading…",
            }
        >
            {move || match bookmarked.get() {
                Some(true) => "★",
                _ => "☆",
            }}
        </button>
    }
}
