use dioxus::prelude::*;
use dioxus_free_icons::icons::bs_icons::*;
use dioxus_free_icons::Icon;

use crate::components::page_header::PageHeader;
use crate::components::toast::{ToastType, Toasts};
use crate::infrastructure::mcp_tokens::{
    create_mcp_token, fetch_mcp_tokens, revoke_mcp_token, CreateMcpTokenResponse,
};

#[component]
pub fn McpTokensPage() -> Element {
    let mut tokens = use_resource(|| async { fetch_mcp_tokens().await.ok() });
    let mut toasts = use_context::<Toasts>();

    // Create-form state
    let mut show_form = use_signal(|| false);
    let mut new_name = use_signal(String::new);
    let mut submitting = use_signal(|| false);

    // After creation, the raw token shows once in a banner
    let mut just_created: Signal<Option<CreateMcpTokenResponse>> = use_signal(|| None);

    // Revoke confirmation: (id, name)
    let mut confirm_revoke: Signal<Option<(String, String)>> = use_signal(|| None);

    rsx! {
        PageHeader {
            title: "MCP Tokens",
            description: "Static bearer tokens for the MCP server. Use in your LLM client (Claude Desktop, Cursor, etc.) — one token per tool/device.",
        }

        // ── Just-created banner ────────────────────────────────────
        if let Some(resp) = just_created() {
            div { class: "card mb-4", style: "border: 1px solid var(--accent-warning); background: var(--bg-warning-subtle);",
                div { class: "card-header", style: "color: var(--accent-warning);",
                    Icon { icon: BsExclamationTriangle, width: 14, height: 14 }
                    " Copy this token now — it won't be shown again"
                }
                div { style: "padding: 1rem;",
                    p { style: "margin-bottom: 0.5rem; color: var(--text-secondary);",
                        "Token for "
                        strong { "{resp.view.name}" }
                    }
                    div { class: "copyable", style: "background: var(--bg-secondary); padding: 0.75rem; border-radius: 4px;",
                        code { style: "font-family: var(--font-mono); word-break: break-all; flex: 1;", "{resp.token}" }
                        crate::components::copy_button::CopyButton { value: resp.token.clone(), small: false }
                    }
                    div { style: "margin-top: 0.75rem;",
                        button {
                            class: "btn btn-sm btn-ghost",
                            onclick: move |_| just_created.set(None),
                            "Dismiss"
                        }
                    }
                }
            }
        }

        // ── Create form ────────────────────────────────────────────
        div { class: "mb-4",
            button {
                class: "btn btn-primary",
                onclick: move |_| {
                    show_form.set(!show_form());
                    new_name.set(String::new());
                },
                if show_form() { "Cancel" } else {
                    Icon { icon: BsPlusLg, width: 14, height: 14 }
                    " Create Token"
                }
            }
        }

        if show_form() {
            div { class: "card mb-4",
                div { class: "card-header", "New MCP Token" }
                div { style: "padding: 1rem;",
                    div { class: "form-group",
                        label { "Name" }
                        input {
                            r#type: "text",
                            placeholder: "Claude Desktop on my laptop",
                            value: "{new_name}",
                            oninput: move |e| new_name.set(e.value()),
                        }
                        small { style: "color: var(--text-secondary);", "A label so you can identify this token in the list. Not visible to LLM clients." }
                    }
                    div { style: "margin-top: 1rem;",
                        button {
                            class: "btn btn-primary",
                            disabled: submitting() || new_name().trim().is_empty(),
                            onclick: move |_| {
                                let name = new_name().trim().to_string();
                                if name.is_empty() {
                                    return;
                                }
                                spawn(async move {
                                    submitting.set(true);
                                    match create_mcp_token(name).await {
                                        Ok(resp) => {
                                            toasts.push(ToastType::Success, "Token created. Copy it now — it won't be shown again.");
                                            just_created.set(Some(resp));
                                            show_form.set(false);
                                            new_name.set(String::new());
                                            tokens.restart();
                                        }
                                        Err(e) => {
                                            toasts.push(ToastType::Error, format!("Failed to create token: {e}"));
                                        }
                                    }
                                    submitting.set(false);
                                });
                            },
                            if submitting() { "Creating..." } else { "Create" }
                        }
                    }
                }
            }
        }

        // ── Tokens list ────────────────────────────────────────────
        match &*tokens.read() {
            Some(Some(resp)) => {
                if resp.data.is_empty() {
                    rsx! {
                        div { class: "card",
                            p { style: "padding: 1rem; color: var(--text-secondary);", "No MCP tokens yet. Create one to start using the MCP server from an LLM client." }
                        }
                    }
                } else {
                    rsx! {
                        div { class: "mcp-cards-grid",
                            for token in resp.data.iter() {
                                {
                                    let id = token.id.clone();
                                    let name = token.name.clone();
                                    let prefix = token.token_prefix.clone();
                                    let created_str = format_timestamp(&token.created_at);
                                    let last_used_str = token
                                        .last_used_at
                                        .as_ref()
                                        .map(format_timestamp)
                                        .unwrap_or_else(|| "never".to_string());
                                    let revoked = token.revoked;
                                    rsx! {
                                        div { class: "mcp-card", style: if revoked { "opacity: 0.55;" } else { "" },
                                            div { class: "mcp-card-header",
                                                div { class: "mcp-card-title",
                                                    Icon { icon: BsKey, width: 14, height: 14 }
                                                    h3 { "{name}" }
                                                    if revoked {
                                                        span { class: "mcp-card-status stopped", "revoked" }
                                                    }
                                                }
                                                if !revoked {
                                                    button {
                                                        class: "btn btn-sm btn-ghost btn-ghost-danger",
                                                        title: "Revoke token",
                                                        onclick: {
                                                            let id = id.clone();
                                                            let name = name.clone();
                                                            move |_| {
                                                                confirm_revoke.set(Some((id.clone(), name.clone())));
                                                            }
                                                        },
                                                        Icon { icon: BsTrash, width: 14, height: 14 }
                                                    }
                                                }
                                            }
                                            div { class: "mcp-card-details",
                                                div { class: "mcp-detail-row",
                                                    Icon { icon: BsKey, width: 13, height: 13 }
                                                    span { class: "mcp-detail-label", "Prefix" }
                                                    code { class: "mcp-detail-value", "{prefix}…" }
                                                }
                                                div { class: "mcp-detail-row",
                                                    Icon { icon: BsCalendar, width: 13, height: 13 }
                                                    span { class: "mcp-detail-label", "Created" }
                                                    span { class: "mcp-detail-value", "{created_str}" }
                                                }
                                                div { class: "mcp-detail-row",
                                                    Icon { icon: BsClockHistory, width: 13, height: 13 }
                                                    span { class: "mcp-detail-label", "Last used" }
                                                    span { class: "mcp-detail-value", "{last_used_str}" }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            Some(None) => rsx! {
                div { class: "card",
                    p { style: "padding: 1rem; color: var(--accent-danger);", "Failed to load MCP tokens." }
                }
            },
            None => rsx! {
                div { class: "card",
                    p { style: "padding: 1rem; color: var(--text-secondary);", "Loading..." }
                }
            },
        }

        // ── Revoke confirmation modal ──────────────────────────────
        if let Some((id, name)) = confirm_revoke() {
            div { class: "modal-overlay",
                div { class: "modal",
                    h3 { "Revoke token?" }
                    p {
                        "The token "
                        strong { "{name}" }
                        " will stop working immediately. This cannot be undone. Any LLM client using it will start getting 401."
                    }
                    div { style: "display: flex; gap: 0.5rem; margin-top: 1rem; justify-content: flex-end;",
                        button {
                            class: "btn btn-ghost",
                            onclick: move |_| confirm_revoke.set(None),
                            "Cancel"
                        }
                        button {
                            class: "btn btn-danger",
                            onclick: {
                                let id = id.clone();
                                move |_| {
                                    let id = id.clone();
                                    spawn(async move {
                                        match revoke_mcp_token(id).await {
                                            Ok(()) => {
                                                toasts.push(ToastType::Success, "Token revoked");
                                                tokens.restart();
                                            }
                                            Err(e) => {
                                                toasts.push(ToastType::Error, format!("Failed to revoke: {e}"));
                                            }
                                        }
                                        confirm_revoke.set(None);
                                    });
                                }
                            },
                            "Revoke"
                        }
                    }
                }
            }
        }
    }
}

/// Best-effort timestamp formatter. The agent serializes BSON DateTime
/// as `{"$date":{"$numberLong":"..."}}` in extended JSON. We accept
/// that shape, plain ISO strings, or anything else (best-effort).
fn format_timestamp(v: &serde_json::Value) -> String {
    if let Some(s) = v.as_str() {
        return s.to_string();
    }
    if let Some(ms) = v
        .get("$date")
        .and_then(|d| d.get("$numberLong"))
        .and_then(|s| s.as_str())
        .and_then(|s| s.parse::<i64>().ok())
    {
        return chrono::DateTime::<chrono::Utc>::from_timestamp_millis(ms)
            .map(|d| d.format("%Y-%m-%d %H:%M").to_string())
            .unwrap_or_else(|| ms.to_string());
    }
    "—".to_string()
}
