//! Admin-specific Leptos components.

use leptos::prelude::*;

// =============================================================================
// Auth Context Types (for sidebar rendering)
// These are duplicated from api/auth.rs because api is SSR-only
// =============================================================================

/// Realm info for auth context.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct ManagedRealm {
    pub slug: String,
    pub name: String,
}

/// Auth context response for the frontend.
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
pub struct AuthContextResponse {
    pub is_server_staff: bool,
    pub managed_realms: Vec<ManagedRealm>,
}

/// Admin layout with sidebar navigation.
///
/// Note: CSS must be loaded by the parent app:
/// - chattyness-owner: Loads `/static/chattyness-owner.css` in AdminApp
/// - chattyness-app: Loads `/admin.css` in lazy wrapper functions
#[component]
pub fn AdminLayout(
    /// Current page identifier for nav highlighting
    current_page: &'static str,
    /// Base path for navigation links (e.g., "/admin")
    #[prop(default = "/admin")]
    base_path: &'static str,
    /// Whether the user is server staff (shows all server-level options)
    #[prop(default = false)]
    is_server_staff: bool,
    /// Realms this user can manage (slug, name pairs)
    #[prop(default = vec![])]
    managed_realms: Vec<(String, String)>,
    /// Page content
    children: Children,
) -> impl IntoView {
    view! {
        <div class="admin-layout">
            <Sidebar
                current_page=current_page
                base_path=base_path
                is_server_staff=is_server_staff
                managed_realms=managed_realms
            />
            <main class="admin-content">
                {children()}
            </main>
        </div>
    }
}

/// Login page layout (no sidebar).
#[component]
pub fn LoginLayout(children: Children) -> impl IntoView {
    view! {
        <div class="login-layout">
            {children()}
        </div>
    }
}

/// Fetch auth context from API (for client-side use).
///
/// The API path is determined dynamically based on the current URL:
/// - If at `/admin/...`, uses `/api/admin/auth/context`
/// - If at root, uses `/api/auth/context`
pub fn use_auth_context() -> LocalResource<Option<AuthContextResponse>> {
    LocalResource::new(move || async move {
        #[cfg(feature = "hydrate")]
        {
            use gloo_net::http::Request;

            // Determine API base path from current URL
            let api_path = web_sys::window()
                .and_then(|w| w.location().pathname().ok())
                .map(|path| {
                    if path.starts_with("/admin") {
                        "/api/admin/auth/context".to_string()
                    } else {
                        "/api/auth/context".to_string()
                    }
                })
                .unwrap_or_else(|| "/api/auth/context".to_string());

            let resp = Request::get(&api_path).send().await;
            match resp {
                Ok(r) if r.ok() => r.json::<AuthContextResponse>().await.ok(),
                _ => None,
            }
        }
        #[cfg(not(feature = "hydrate"))]
        {
            None::<AuthContextResponse>
        }
    })
}

/// Authenticated admin layout that fetches auth context.
///
/// This wrapper fetches the current user's auth context and passes it to
/// AdminLayout for proper sidebar rendering.
#[component]
pub fn AuthenticatedLayout(
    current_page: &'static str,
    #[prop(default = "/admin")] base_path: &'static str,
    children: ChildrenFn,
) -> impl IntoView {
    let auth_context = use_auth_context();

    view! {
        <Suspense fallback=move || view! {
            <AdminLayout current_page=current_page base_path=base_path>
                <div class="loading-container">
                    <p>"Loading..."</p>
                </div>
            </AdminLayout>
        }>
            {move || {
                let children = children.clone();
                auth_context.get().map(move |maybe_ctx| {
                    let children = children.clone();
                    match maybe_ctx {
                        Some(ctx) => {
                            let managed_realms: Vec<(String, String)> = ctx.managed_realms
                                .into_iter()
                                .map(|r| (r.slug, r.name))
                                .collect();
                            view! {
                                <AdminLayout
                                    current_page=current_page
                                    base_path=base_path
                                    is_server_staff=ctx.is_server_staff
                                    managed_realms=managed_realms
                                >
                                    {children()}
                                </AdminLayout>
                            }.into_any()
                        }
                        None => {
                            // Fallback: show layout with default props (server staff view)
                            view! {
                                <AdminLayout current_page=current_page base_path=base_path is_server_staff=true>
                                    {children()}
                                </AdminLayout>
                            }.into_any()
                        }
                    }
                })
            }}
        </Suspense>
    }
}

/// Sidebar navigation component.
#[component]
fn Sidebar(
    current_page: &'static str,
    base_path: &'static str,
    #[prop(default = false)] is_server_staff: bool,
    #[prop(default = vec![])] managed_realms: Vec<(String, String)>,
) -> impl IntoView {
    // Build hrefs with base path
    let dashboard_href = base_path.to_string();
    let config_href = format!("{}/config", base_path);
    let users_href = format!("{}/users", base_path);
    let users_new_href = format!("{}/users/new", base_path);
    let staff_href = format!("{}/staff", base_path);
    let realms_href = format!("{}/realms", base_path);
    let realms_new_href = format!("{}/realms/new", base_path);
    let props_href = format!("{}/props", base_path);
    let props_new_href = format!("{}/props/new", base_path);

    view! {
        <nav class="sidebar">
            <div class="sidebar-header">
                <a href="/admin" class="sidebar-brand">"Chattyness"</a>
                <span class="sidebar-badge">"Admin"</span>
            </div>

            <ul class="nav-list">
                // Server staff: show all server-level options
                {if is_server_staff {
                    view! {
                        <NavItem
                            href=dashboard_href.clone()
                            label="Dashboard"
                            active=current_page == "dashboard"
                        />
                        <NavItem
                            href=config_href.clone()
                            label="Server Config"
                            active=current_page == "config"
                        />

                        <li class="nav-section">
                            <span class="nav-section-title">"User Management"</span>
                            <ul class="nav-sublist">
                                <NavItem
                                    href=users_href.clone()
                                    label="All Users"
                                    active=current_page == "users"
                                    sub=true
                                />
                                <NavItem
                                    href=users_new_href.clone()
                                    label="Create User"
                                    active=current_page == "users_new"
                                    sub=true
                                />
                                <NavItem
                                    href=staff_href.clone()
                                    label="Staff"
                                    active=current_page == "staff"
                                    sub=true
                                />
                            </ul>
                        </li>

                        <li class="nav-section">
                            <span class="nav-section-title">"Realm Management"</span>
                            <ul class="nav-sublist">
                                <NavItem
                                    href=realms_href.clone()
                                    label="All Realms"
                                    active=current_page == "realms"
                                    sub=true
                                />
                                <NavItem
                                    href=realms_new_href.clone()
                                    label="Create Realm"
                                    active=current_page == "realms_new"
                                    sub=true
                                />
                            </ul>
                        </li>

                        <li class="nav-section">
                            <span class="nav-section-title">"Props"</span>
                            <ul class="nav-sublist">
                                <NavItem
                                    href=props_href.clone()
                                    label="All Props"
                                    active=current_page == "props"
                                    sub=true
                                />
                                <NavItem
                                    href=props_new_href.clone()
                                    label="Create Prop"
                                    active=current_page == "props_new"
                                    sub=true
                                />
                            </ul>
                        </li>
                    }.into_any()
                } else {
                    // Realm admin: show realm-specific options only
                    view! {
                        {managed_realms.into_iter().map(|(slug, name)| {
                            let scenes_href = format!("{}/realms/{}/scenes", base_path, slug);
                            let scenes_new_href = format!("{}/realms/{}/scenes/new", base_path, slug);
                            let realm_settings_href = format!("{}/realms/{}", base_path, slug);

                            view! {
                                <li class="nav-section">
                                    <span class="nav-section-title">{name}</span>
                                    <ul class="nav-sublist">
                                        <NavItem
                                            href=scenes_href
                                            label="Scenes"
                                            active=current_page == "scenes"
                                            sub=true
                                        />
                                        <NavItem
                                            href=scenes_new_href
                                            label="Create Scene"
                                            active=current_page == "scenes_new"
                                            sub=true
                                        />
                                        <NavItem
                                            href=realm_settings_href
                                            label="Realm Settings"
                                            active=current_page == "realms"
                                            sub=true
                                        />
                                    </ul>
                                </li>
                            }
                        }).collect::<Vec<_>>()}
                    }.into_any()
                }}
            </ul>

            <div class="sidebar-footer">
                <button type="button" class="sidebar-logout" id="logout-btn">
                    "Logout"
                </button>
            </div>
        </nav>
    }
}

/// Navigation item component.
///
/// Supports both static and dynamic hrefs via `#[prop(into)]`.
#[component]
fn NavItem(
    #[prop(into)] href: String,
    label: &'static str,
    #[prop(default = false)] active: bool,
    /// Whether this is a sub-item (indented)
    #[prop(default = false)]
    sub: bool,
) -> impl IntoView {
    let link_class = match (active, sub) {
        (true, false) => {
            "block w-full px-6 py-2 bg-violet-600 text-white transition-all duration-150"
        }
        (false, false) => {
            "block w-full px-6 py-2 text-gray-400 hover:bg-slate-700 hover:text-white transition-all duration-150"
        }
        (true, true) => {
            "block w-full pl-10 pr-6 py-2 text-sm bg-violet-600 text-white transition-all duration-150"
        }
        (false, true) => {
            "block w-full pl-10 pr-6 py-2 text-sm text-gray-400 hover:bg-slate-700 hover:text-white transition-all duration-150"
        }
    };

    view! {
        <li class="my-0.5">
            <a href=href class=link_class>{label}</a>
        </li>
    }
}

/// Page header component.
#[component]
pub fn PageHeader(
    /// Page title
    title: &'static str,
    /// Optional subtitle (accepts String or &str)
    #[prop(optional, into)]
    subtitle: String,
    /// Optional action buttons
    #[prop(optional)]
    children: Option<Children>,
) -> impl IntoView {
    let has_subtitle = !subtitle.is_empty();

    view! {
        <header class="page-header">
            <div class="page-header-text">
                <h1 class="page-title">{title}</h1>
                {if has_subtitle {
                    view! { <p class="page-subtitle">{subtitle}</p> }.into_any()
                } else {
                    view! {}.into_any()
                }}
            </div>
            {if let Some(children) = children {
                view! {
                    <div class="page-header-actions">
                        {children()}
                    </div>
                }.into_any()
            } else {
                view! {}.into_any()
            }}
        </header>
    }
}

/// Card component.
#[component]
pub fn Card(
    #[prop(optional)] title: &'static str,
    #[prop(optional)] class: &'static str,
    children: Children,
) -> impl IntoView {
    let has_title = !title.is_empty();
    let card_class = if class.is_empty() {
        "card".to_string()
    } else {
        format!("card {}", class)
    };

    view! {
        <div class=card_class>
            {if has_title {
                view! { <h2 class="card-title">{title}</h2> }.into_any()
            } else {
                view! {}.into_any()
            }}
            {children()}
        </div>
    }
}

/// Detail grid for key-value display.
#[component]
pub fn DetailGrid(children: Children) -> impl IntoView {
    view! {
        <div class="detail-grid">
            {children()}
        </div>
    }
}

/// Detail item within a detail grid.
#[component]
pub fn DetailItem(label: &'static str, children: Children) -> impl IntoView {
    view! {
        <div class="detail-item">
            <div class="detail-label">{label}</div>
            <div class="detail-value">{children()}</div>
        </div>
    }
}

/// Status badge component.
#[component]
pub fn StatusBadge(
    /// Status text
    status: String,
) -> impl IntoView {
    let class = format!("status-badge status-{}", status.to_lowercase());
    view! {
        <span class=class>{status}</span>
    }
}

/// Privacy badge component.
#[component]
pub fn PrivacyBadge(
    /// Privacy level
    privacy: String,
) -> impl IntoView {
    let class = format!("privacy-badge privacy-{}", privacy.to_lowercase());
    view! {
        <span class=class>{privacy}</span>
    }
}

/// NSFW badge component.
#[component]
pub fn NsfwBadge() -> impl IntoView {
    view! {
        <span class="nsfw-badge">"NSFW"</span>
    }
}

/// Empty state placeholder.
#[component]
pub fn EmptyState(
    message: &'static str,
    #[prop(optional)] action_href: &'static str,
    #[prop(optional)] action_text: &'static str,
) -> impl IntoView {
    let has_action = !action_href.is_empty() && !action_text.is_empty();

    view! {
        <div class="empty-state">
            <p>{message}</p>
            {if has_action {
                view! {
                    <a href=action_href class="btn btn-primary">{action_text}</a>
                }.into_any()
            } else {
                view! {}.into_any()
            }}
        </div>
    }
}

/// Alert message component.
#[component]
pub fn Alert(
    /// Alert variant: success, error, warning, info
    variant: &'static str,
    /// Alert message
    message: String,
) -> impl IntoView {
    let class = format!("alert alert-{}", variant);
    view! {
        <div class=class role="alert">
            <p>{message}</p>
        </div>
    }
}

/// Message alert that shows/hides based on signal state.
///
/// This component reduces the boilerplate for showing form feedback messages.
/// The message signal contains `Option<(String, bool)>` where bool is `is_success`.
#[component]
pub fn MessageAlert(message: ReadSignal<Option<(String, bool)>>) -> impl IntoView {
    view! {
        <Show when=move || message.get().is_some()>
            {move || {
                let (msg, is_success) = message.get().unwrap_or_default();
                let class = if is_success { "alert alert-success" } else { "alert alert-error" };
                view! {
                    <div class=class role="alert">
                        <p>{msg}</p>
                    </div>
                }
            }}
        </Show>
    }
}

/// Message alert that works with RwSignal.
#[component]
pub fn MessageAlertRw(message: RwSignal<Option<(String, bool)>>) -> impl IntoView {
    view! {
        <Show when=move || message.get().is_some()>
            {move || {
                let (msg, is_success) = message.get().unwrap_or_default();
                let class = if is_success { "alert alert-success" } else { "alert alert-error" };
                view! {
                    <div class=class role="alert">
                        <p>{msg}</p>
                    </div>
                }
            }}
        </Show>
    }
}

/// Temporary password display component.
///
/// Shows the temporary password with a warning to copy it.
#[component]
pub fn TempPasswordDisplay(
    /// The temporary password signal
    password: ReadSignal<Option<String>>,
    /// Optional label (default: "Temporary Password:")
    #[prop(default = "Temporary Password:")]
    label: &'static str,
) -> impl IntoView {
    view! {
        <Show when=move || password.get().is_some()>
            <div class="alert alert-info">
                <p><strong>{label}</strong></p>
                <code class="temp-password">{move || password.get().unwrap_or_default()}</code>
                <p class="text-muted">"Copy this password now - it will not be shown again!"</p>
            </div>
        </Show>
    }
}

/// Delete confirmation component with danger zone styling.
///
/// Shows a button that reveals a confirmation dialog when clicked.
#[component]
pub fn DeleteConfirmation(
    /// Warning message to show
    message: &'static str,
    /// Button text (default: "Delete")
    #[prop(default = "Delete")]
    button_text: &'static str,
    /// Confirm button text (default: "Yes, Delete")
    #[prop(default = "Yes, Delete")]
    confirm_text: &'static str,
    /// Pending state signal
    pending: ReadSignal<bool>,
    /// Callback when delete is confirmed
    on_confirm: impl Fn() + Clone + Send + Sync + 'static,
) -> impl IntoView {
    let (show_confirm, set_show_confirm) = signal(false);
    let on_confirm_clone = on_confirm.clone();

    view! {
        <Show
            when=move || !show_confirm.get()
            fallback=move || {
                let on_confirm = on_confirm_clone.clone();
                view! {
                    <div class="alert alert-warning">
                        <p>{message}</p>
                        <div class="action-buttons">
                            <button
                                type="button"
                                class="btn btn-danger"
                                disabled=move || pending.get()
                                on:click=move |_| on_confirm()
                            >
                                {move || if pending.get() { "Deleting..." } else { confirm_text }}
                            </button>
                            <button
                                type="button"
                                class="btn btn-secondary"
                                on:click=move |_| set_show_confirm.set(false)
                            >
                                "Cancel"
                            </button>
                        </div>
                    </div>
                }
            }
        >
            <button
                type="button"
                class="btn btn-danger"
                on:click=move |_| set_show_confirm.set(true)
            >
                {button_text}
            </button>
        </Show>
    }
}

/// Submit button with loading state.
#[component]
pub fn SubmitButton(
    /// Button text when not pending
    text: &'static str,
    /// Button text when pending (default adds "...")
    #[prop(optional)]
    pending_text: Option<&'static str>,
    /// Whether the button is in pending state
    pending: ReadSignal<bool>,
    /// Additional CSS classes
    #[prop(default = "btn btn-primary")]
    class: &'static str,
) -> impl IntoView {
    let loading_text = pending_text.unwrap_or_else(|| {
        // Can't do string manipulation at compile time, so use a simple approach
        text
    });

    view! {
        <button
            type="submit"
            class=class
            disabled=move || pending.get()
        >
            {move || if pending.get() { loading_text } else { text }}
        </button>
    }
}

/// Loading spinner.
#[component]
pub fn LoadingSpinner(#[prop(optional)] message: &'static str) -> impl IntoView {
    view! {
        <div class="loading-spinner">
            <div class="spinner"></div>
            {if !message.is_empty() {
                view! { <span class="loading-message">{message}</span> }.into_any()
            } else {
                view! {}.into_any()
            }}
        </div>
    }
}

/// Role badge component.
#[component]
pub fn RoleBadge(role: String) -> impl IntoView {
    let class = format!("role-badge role-{}", role.to_lowercase());
    view! {
        <span class=class>{role}</span>
    }
}

/// Pagination component.
#[component]
pub fn Pagination(current_page: i64, base_url: String, query: String) -> impl IntoView {
    let prev_page = current_page - 1;
    let next_page = current_page + 1;

    let prev_url = if query.is_empty() {
        format!("{}?page={}", base_url, prev_page)
    } else {
        format!("{}?q={}&page={}", base_url, query, prev_page)
    };

    let next_url = if query.is_empty() {
        format!("{}?page={}", base_url, next_page)
    } else {
        format!("{}?q={}&page={}", base_url, query, next_page)
    };

    view! {
        <nav class="pagination">
            {if current_page > 1 {
                view! {
                    <a href=prev_url class="btn btn-secondary">"Previous"</a>
                }.into_any()
            } else {
                view! {
                    <span class="btn btn-secondary btn-disabled">"Previous"</span>
                }.into_any()
            }}
            <span class="pagination-info">"Page " {current_page}</span>
            <a href=next_url class="btn btn-secondary">"Next"</a>
        </nav>
    }
}

/// Search form component for list pages.
#[component]
pub fn SearchForm(
    /// Form action URL (e.g., "/admin/users")
    action: &'static str,
    /// Placeholder text
    placeholder: &'static str,
    /// Current search value signal
    search_input: RwSignal<String>,
) -> impl IntoView {
    view! {
        <form method="get" action=action class="search-form">
            <div class="search-box">
                <input
                    type="search"
                    name="q"
                    placeholder=placeholder
                    class="form-input search-input"
                    prop:value=move || search_input.get()
                    on:input=move |ev| search_input.set(event_target_value(&ev))
                />
                <button type="submit" class="btn btn-primary">"Search"</button>
            </div>
        </form>
    }
}
