//! Avatar store popup component.
//!
//! Allows users to browse and select pre-configured server and realm avatars.

use leptos::prelude::*;
use uuid::Uuid;

use chattyness_db::models::{RealmAvatarWithPaths, ServerAvatarWithPaths};

use super::avatar_thumbnail::AvatarThumbnail;
use super::modals::{GuestLockedOverlay, Modal};
use super::tabs::{Tab, TabBar};

/// Avatar store popup component.
///
/// Shows a tabbed interface with:
/// - Server Avatars: Public server-wide pre-configured avatars
/// - Realm Avatars: Public realm-specific pre-configured avatars
///
/// Props:
/// - `open`: Signal controlling visibility
/// - `on_close`: Callback when popup should close
/// - `realm_slug`: Current realm slug for API calls
/// - `is_guest`: Whether the current user is a guest (shows locked overlay)
/// - `on_avatar_selected`: Callback when an avatar is successfully selected
#[component]
pub fn AvatarStorePopup(
    #[prop(into)] open: Signal<bool>,
    on_close: Callback<()>,
    #[prop(into)] realm_slug: Signal<String>,
    /// Whether the current user is a guest. Guests see a locked overlay.
    #[prop(optional, into)]
    is_guest: Option<Signal<bool>>,
    /// Callback fired when an avatar is successfully selected (for refreshing avatar state).
    #[prop(optional, into)]
    on_avatar_selected: Option<Callback<()>>,
) -> impl IntoView {
    let is_guest = is_guest.unwrap_or_else(|| Signal::derive(|| false));

    // Tab state
    let (active_tab, set_active_tab) = signal("server");

    // Server avatars state
    let (server_avatars, set_server_avatars) = signal(Vec::<ServerAvatarWithPaths>::new());
    let (server_loading, set_server_loading) = signal(false);
    let (server_error, set_server_error) = signal(Option::<String>::None);
    let (selected_server_avatar, set_selected_server_avatar) = signal(Option::<Uuid>::None);

    // Realm avatars state
    let (realm_avatars, set_realm_avatars) = signal(Vec::<RealmAvatarWithPaths>::new());
    let (realm_loading, set_realm_loading) = signal(false);
    let (realm_error, set_realm_error) = signal(Option::<String>::None);
    let (selected_realm_avatar, set_selected_realm_avatar) = signal(Option::<Uuid>::None);

    // Track if tabs have been loaded
    let (server_loaded, set_server_loaded) = signal(false);
    let (realm_loaded, set_realm_loaded) = signal(false);

    // Selection state
    let (selecting, set_selecting) = signal(false);
    let (selection_error, set_selection_error) = signal(Option::<String>::None);

    // Fetch server avatars when popup opens or tab is selected
    #[cfg(feature = "hydrate")]
    {
        use gloo_net::http::Request;
        use leptos::task::spawn_local;

        Effect::new(move |_| {
            if !open.get() {
                // Reset state when closing
                set_selected_server_avatar.set(None);
                set_selected_realm_avatar.set(None);
                set_server_loaded.set(false);
                set_realm_loaded.set(false);
                set_selection_error.set(None);
                return;
            }

            // Only fetch if on server tab and not already loaded
            if active_tab.get() != "server" || server_loaded.get() {
                return;
            }

            set_server_loading.set(true);
            set_server_error.set(None);

            spawn_local(async move {
                let response = Request::get("/api/server/avatars").send().await;
                match response {
                    Ok(resp) if resp.ok() => {
                        if let Ok(data) = resp.json::<Vec<ServerAvatarWithPaths>>().await {
                            set_server_avatars.set(data);
                            set_server_loaded.set(true);
                        } else {
                            set_server_error.set(Some("Failed to parse server avatars".to_string()));
                        }
                    }
                    Ok(resp) => {
                        set_server_error.set(Some(format!(
                            "Failed to load server avatars: {}",
                            resp.status()
                        )));
                    }
                    Err(e) => {
                        set_server_error.set(Some(format!("Network error: {}", e)));
                    }
                }
                set_server_loading.set(false);
            });
        });
    }

    // Fetch realm avatars when realm tab is selected
    #[cfg(feature = "hydrate")]
    {
        use gloo_net::http::Request;
        use leptos::task::spawn_local;

        Effect::new(move |_| {
            if !open.get() || active_tab.get() != "realm" || realm_loaded.get() {
                return;
            }

            let slug = realm_slug.get();
            if slug.is_empty() {
                set_realm_error.set(Some("No realm selected".to_string()));
                return;
            }

            set_realm_loading.set(true);
            set_realm_error.set(None);

            spawn_local(async move {
                let response = Request::get(&format!("/api/realms/{}/avatars", slug))
                    .send()
                    .await;
                match response {
                    Ok(resp) if resp.ok() => {
                        if let Ok(data) = resp.json::<Vec<RealmAvatarWithPaths>>().await {
                            set_realm_avatars.set(data);
                            set_realm_loaded.set(true);
                        } else {
                            set_realm_error.set(Some("Failed to parse realm avatars".to_string()));
                        }
                    }
                    Ok(resp) => {
                        set_realm_error.set(Some(format!(
                            "Failed to load realm avatars: {}",
                            resp.status()
                        )));
                    }
                    Err(e) => {
                        set_realm_error.set(Some(format!("Network error: {}", e)));
                    }
                }
                set_realm_loading.set(false);
            });
        });
    }

    // Handle avatar selection
    #[cfg(feature = "hydrate")]
    let select_avatar = {
        let on_avatar_selected = on_avatar_selected.clone();
        Callback::new(move |(avatar_id, source): (Uuid, &'static str)| {
            set_selecting.set(true);
            set_selection_error.set(None);

            let slug = realm_slug.get();
            let on_avatar_selected = on_avatar_selected.clone();

            leptos::task::spawn_local(async move {
                use gloo_net::http::Request;

                let body = serde_json::json!({
                    "avatar_id": avatar_id,
                    "source": source
                });

                let response = Request::post(&format!("/api/realms/{}/avatar/select", slug))
                    .header("Content-Type", "application/json")
                    .body(body.to_string())
                    .unwrap()
                    .send()
                    .await;

                match response {
                    Ok(resp) if resp.ok() => {
                        // Notify parent of successful selection
                        if let Some(callback) = on_avatar_selected {
                            callback.run(());
                        }
                        set_selection_error.set(None);
                    }
                    Ok(resp) => {
                        if let Ok(error_json) = resp.json::<serde_json::Value>().await {
                            let error_msg = error_json
                                .get("error")
                                .and_then(|e| e.as_str())
                                .unwrap_or("Unknown error");
                            set_selection_error.set(Some(error_msg.to_string()));
                        } else {
                            set_selection_error.set(Some(format!(
                                "Failed to select avatar: {}",
                                resp.status()
                            )));
                        }
                    }
                    Err(e) => {
                        set_selection_error.set(Some(format!("Network error: {}", e)));
                    }
                }
                set_selecting.set(false);
            });
        })
    };

    #[cfg(not(feature = "hydrate"))]
    let select_avatar = Callback::new(|_: (Uuid, &'static str)| {});

    // Handle clear selection
    #[cfg(feature = "hydrate")]
    let clear_selection = {
        let on_avatar_selected = on_avatar_selected.clone();
        Callback::new(move |_: ()| {
            set_selecting.set(true);
            set_selection_error.set(None);

            let slug = realm_slug.get();
            let on_avatar_selected = on_avatar_selected.clone();

            leptos::task::spawn_local(async move {
                use gloo_net::http::Request;

                let response = Request::delete(&format!("/api/realms/{}/avatar/selection", slug))
                    .send()
                    .await;

                match response {
                    Ok(resp) if resp.ok() => {
                        // Notify parent of successful clear
                        if let Some(callback) = on_avatar_selected {
                            callback.run(());
                        }
                        set_selection_error.set(None);
                    }
                    Ok(resp) => {
                        set_selection_error.set(Some(format!(
                            "Failed to clear selection: {}",
                            resp.status()
                        )));
                    }
                    Err(e) => {
                        set_selection_error.set(Some(format!("Network error: {}", e)));
                    }
                }
                set_selecting.set(false);
            });
        })
    };

    #[cfg(not(feature = "hydrate"))]
    let clear_selection = Callback::new(|_: ()| {});

    view! {
        <Modal
            open=open
            on_close=on_close
            title="Avatar Store"
            title_id="avatar-store-modal-title"
            max_width="max-w-2xl"
            class="max-h-[80vh] flex flex-col"
        >
            <div class="relative flex-1 flex flex-col">
                // Tab bar
                <TabBar
                    tabs=vec![
                        Tab::new("server", "Server Avatars"),
                        Tab::new("realm", "Realm Avatars"),
                    ]
                    active=Signal::derive(move || active_tab.get())
                    on_select=Callback::new(move |id| set_active_tab.set(id))
                />

                // Selection error message
                <Show when=move || selection_error.get().is_some()>
                    <div class="bg-red-900/20 border border-red-600 rounded p-3 mx-4 mb-2">
                        <p class="text-red-400 text-sm">{move || selection_error.get().unwrap_or_default()}</p>
                    </div>
                </Show>

                // Tab content
                <div class="flex-1 overflow-y-auto min-h-[300px]">
                    // Server Avatars tab
                    <Show when=move || active_tab.get() == "server">
                        <AvatarsTab
                            avatars=Signal::derive(move || server_avatars.get().into_iter().map(|a| AvatarInfo {
                                id: a.id,
                                name: a.name,
                                description: a.description,
                                skin_layer: a.skin_layer,
                                clothes_layer: a.clothes_layer,
                                accessories_layer: a.accessories_layer,
                                emotion_layer: a.emotion_layer,
                            }).collect())
                            loading=server_loading
                            error=server_error
                            selected_id=selected_server_avatar
                            set_selected_id=set_selected_server_avatar
                            source="server"
                            tab_name="Server"
                            empty_message="No public server avatars available"
                            is_guest=is_guest
                            selecting=selecting
                            on_select=select_avatar.clone()
                            on_clear=clear_selection.clone()
                        />
                    </Show>

                    // Realm Avatars tab
                    <Show when=move || active_tab.get() == "realm">
                        <AvatarsTab
                            avatars=Signal::derive(move || realm_avatars.get().into_iter().map(|a| AvatarInfo {
                                id: a.id,
                                name: a.name,
                                description: a.description,
                                skin_layer: a.skin_layer,
                                clothes_layer: a.clothes_layer,
                                accessories_layer: a.accessories_layer,
                                emotion_layer: a.emotion_layer,
                            }).collect())
                            loading=realm_loading
                            error=realm_error
                            selected_id=selected_realm_avatar
                            set_selected_id=set_selected_realm_avatar
                            source="realm"
                            tab_name="Realm"
                            empty_message="No public realm avatars available"
                            is_guest=is_guest
                            selecting=selecting
                            on_select=select_avatar.clone()
                            on_clear=clear_selection.clone()
                        />
                    </Show>
                </div>

                // Guest locked overlay
                <Show when=move || is_guest.get()>
                    <GuestLockedOverlay />
                </Show>
            </div>
        </Modal>
    }
}

/// Simplified avatar info for the grid with resolved paths for rendering.
#[derive(Clone)]
struct AvatarInfo {
    id: Uuid,
    name: String,
    description: Option<String>,
    /// Asset paths for skin layer positions 0-8
    skin_layer: [Option<String>; 9],
    /// Asset paths for clothes layer positions 0-8
    clothes_layer: [Option<String>; 9],
    /// Asset paths for accessories layer positions 0-8
    accessories_layer: [Option<String>; 9],
    /// Asset paths for emotion layer positions 0-8
    emotion_layer: [Option<String>; 9],
}

/// Avatars tab content with selection functionality.
#[component]
fn AvatarsTab(
    #[prop(into)] avatars: Signal<Vec<AvatarInfo>>,
    #[prop(into)] loading: Signal<bool>,
    #[prop(into)] error: Signal<Option<String>>,
    #[prop(into)] selected_id: Signal<Option<Uuid>>,
    set_selected_id: WriteSignal<Option<Uuid>>,
    source: &'static str,
    tab_name: &'static str,
    empty_message: &'static str,
    #[prop(into)] is_guest: Signal<bool>,
    #[prop(into)] selecting: Signal<bool>,
    on_select: Callback<(Uuid, &'static str)>,
    on_clear: Callback<()>,
) -> impl IntoView {
    view! {
        // Loading state
        <Show when=move || loading.get()>
            <div class="flex items-center justify-center py-12">
                <p class="text-gray-400">{format!("Loading {} avatars...", tab_name.to_lowercase())}</p>
            </div>
        </Show>

        // Error state
        <Show when=move || error.get().is_some()>
            <div class="bg-red-900/20 border border-red-600 rounded p-4 mb-4 mx-4">
                <p class="text-red-400">{move || error.get().unwrap_or_default()}</p>
            </div>
        </Show>

        // Empty state
        <Show when=move || !loading.get() && error.get().is_none() && avatars.get().is_empty()>
            <div class="flex flex-col items-center justify-center py-12 text-center">
                <div class="w-16 h-16 rounded-full bg-gray-700/50 flex items-center justify-center mb-4">
                    <svg class="w-8 h-8 text-gray-500" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
                        <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"/>
                    </svg>
                </div>
                <p class="text-gray-400">{empty_message}</p>
                <p class="text-gray-500 text-sm mt-1">"Pre-configured avatars will appear here when available"</p>
            </div>
        </Show>

        // Grid of avatars
        <Show when=move || !loading.get() && !avatars.get().is_empty()>
            <div class="p-4">
                <div
                    class="grid grid-cols-4 sm:grid-cols-6 gap-3"
                    role="listbox"
                    aria-label=format!("{} avatars", tab_name)
                >
                    <For
                        each=move || avatars.get()
                        key=|avatar| avatar.id
                        children=move |avatar: AvatarInfo| {
                            let avatar_id = avatar.id;
                            let avatar_name = avatar.name.clone();
                            let is_selected = move || selected_id.get() == Some(avatar_id);

                            // Create signals for the layer data
                            let skin_layer = Signal::derive({
                                let layers = avatar.skin_layer.clone();
                                move || layers.clone()
                            });
                            let clothes_layer = Signal::derive({
                                let layers = avatar.clothes_layer.clone();
                                move || layers.clone()
                            });
                            let accessories_layer = Signal::derive({
                                let layers = avatar.accessories_layer.clone();
                                move || layers.clone()
                            });
                            let emotion_layer = Signal::derive({
                                let layers = avatar.emotion_layer.clone();
                                move || layers.clone()
                            });

                            view! {
                                <button
                                    type="button"
                                    class=move || format!(
                                        "aspect-square rounded-lg border-2 transition-all p-1 focus:outline-none focus:ring-2 focus:ring-blue-500 {}",
                                        if is_selected() {
                                            "border-blue-500 bg-blue-900/30"
                                        } else {
                                            "border-gray-600 hover:border-gray-500 bg-gray-700/50"
                                        }
                                    )
                                    on:click=move |_| {
                                        set_selected_id.set(Some(avatar_id));
                                    }
                                    role="option"
                                    aria-selected=is_selected
                                    aria-label=avatar_name
                                >
                                    <AvatarThumbnail
                                        skin_layer=skin_layer
                                        clothes_layer=clothes_layer
                                        accessories_layer=accessories_layer
                                        emotion_layer=emotion_layer
                                        size=72
                                    />
                                </button>
                            }
                        }
                    />
                </div>

                // Selected avatar details and actions
                {move || {
                    let avatar_id = selected_id.get()?;
                    let avatar = avatars.get().into_iter().find(|a| a.id == avatar_id)?;
                    let guest = is_guest.get();
                    let is_selecting = selecting.get();

                    let (button_text, button_class, button_disabled, button_title) = if guest {
                        ("Sign in to Select", "bg-gray-600 text-gray-400 cursor-not-allowed", true, "Guests cannot select avatars")
                    } else if is_selecting {
                        ("Selecting...", "bg-blue-600 text-white opacity-50", true, "")
                    } else {
                        ("Select This Avatar", "bg-blue-600 hover:bg-blue-700 text-white", false, "Use this pre-configured avatar")
                    };

                    let avatar_name = avatar.name.clone();
                    let avatar_description = avatar.description.clone();
                    let on_select = on_select.clone();
                    let on_clear = on_clear.clone();

                    Some(view! {
                        <div class="mt-4 pt-4 border-t border-gray-700">
                            <div class="flex items-start justify-between gap-4">
                                <div class="flex-1 min-w-0">
                                    <h3 class="text-white font-medium truncate">{avatar_name}</h3>
                                    {avatar_description.map(|desc| view! {
                                        <p class="text-gray-400 text-sm mt-1 line-clamp-2">{desc}</p>
                                    })}
                                </div>
                                <div class="flex gap-2 flex-shrink-0">
                                    <button
                                        type="button"
                                        class="px-3 py-2 bg-gray-600 hover:bg-gray-700 text-white rounded-lg transition-colors text-sm disabled:opacity-50"
                                        on:click=move |_| {
                                            on_clear.run(());
                                        }
                                        disabled=is_selecting || guest
                                        title="Clear selection and use custom/default avatar"
                                    >
                                        "Clear"
                                    </button>
                                    <button
                                        type="button"
                                        class=format!("px-4 py-2 rounded-lg transition-colors {}", button_class)
                                        on:click=move |_| {
                                            if !button_disabled {
                                                on_select.run((avatar_id, source));
                                            }
                                        }
                                        disabled=button_disabled
                                        title=button_title
                                    >
                                        {button_text}
                                    </button>
                                </div>
                            </div>
                        </div>
                    })
                }}
            </div>
        </Show>
    }
}
