use leptos::prelude::*;
use wasm_bindgen::JsCast;

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TooltipPosition {
    Top,
    Bottom,
    Left,
    Right,
    Auto,
}

#[component]
pub fn ContextualTooltip(
    /// The content to show in the tooltip
    #[prop(into)]
    content: String,

    /// Optional link to documentation
    #[prop(into, optional)]
    docs_link: Option<String>,

    /// Optional example text
    #[prop(into, optional)]
    example: Option<String>,

    /// Position of the tooltip relative to the target
    #[prop(into, optional)]
    position: Option<TooltipPosition>,

    /// Delay before showing tooltip (ms)
    #[prop(into, optional)]
    delay: Option<u32>,

    /// Children elements that trigger the tooltip
    children: Children,
) -> impl IntoView {
    let (is_visible, set_is_visible) = signal(false);
    let (tooltip_position, set_tooltip_position) = signal((0, 0));
    let (actual_position, set_actual_position) = signal(position.unwrap_or(TooltipPosition::Auto));

    let delay_ms = delay.unwrap_or(300);
    let mut show_timeout: Option<i32> = None;

    let calculate_position = move |target: &web_sys::HtmlElement| {
        let rect = target.get_bounding_client_rect();
        let window = web_sys::window().expect("window should exist");
        let window_width = window.inner_width().unwrap().as_f64().unwrap_or(1920.0);
        let window_height = window.inner_height().unwrap().as_f64().unwrap_or(1080.0);

        let tooltip_width = 320.0; // Estimated tooltip width
        let tooltip_height = 150.0; // Estimated tooltip height

        let pos = actual_position.get();

        // Calculate position based on tooltip position setting
        let (x, y, final_pos) = match pos {
            TooltipPosition::Top => (
                rect.left(),
                rect.top() - tooltip_height - 10.0,
                TooltipPosition::Top,
            ),
            TooltipPosition::Bottom => (rect.left(), rect.bottom() + 10.0, TooltipPosition::Bottom),
            TooltipPosition::Left => (
                rect.left() - tooltip_width - 10.0,
                rect.top(),
                TooltipPosition::Left,
            ),
            TooltipPosition::Right => (rect.right() + 10.0, rect.top(), TooltipPosition::Right),
            TooltipPosition::Auto => {
                // Auto-calculate best position
                let space_above = rect.top();
                let space_below = window_height - rect.bottom();
                let space_left = rect.left();
                let space_right = window_width - rect.right();

                if space_below >= tooltip_height + 20.0 {
                    (rect.left(), rect.bottom() + 10.0, TooltipPosition::Bottom)
                } else if space_above >= tooltip_height + 20.0 {
                    (
                        rect.left(),
                        rect.top() - tooltip_height - 10.0,
                        TooltipPosition::Top,
                    )
                } else if space_right >= tooltip_width + 20.0 {
                    (rect.right() + 10.0, rect.top(), TooltipPosition::Right)
                } else if space_left >= tooltip_width + 20.0 {
                    (
                        rect.left() - tooltip_width - 10.0,
                        rect.top(),
                        TooltipPosition::Left,
                    )
                } else {
                    // Default to bottom if no good position
                    (rect.left(), rect.bottom() + 10.0, TooltipPosition::Bottom)
                }
            }
        };

        set_actual_position.set(final_pos);
        set_tooltip_position.set((x as i32, y as i32));
    };

    let handle_mouse_enter = move |ev: web_sys::MouseEvent| {
        if let Some(target) = ev.current_target() {
            if let Ok(element) = target.dyn_into::<web_sys::HtmlElement>() {
                calculate_position(&element);

                // Set timeout to show tooltip after delay
                if delay_ms > 0 {
                    if let Some(window) = web_sys::window() {
                        let set_visible = set_is_visible;
                        let timeout = window
                            .set_timeout_with_callback_and_timeout_and_arguments_0(
                                wasm_bindgen::closure::Closure::wrap(Box::new(move || {
                                    set_visible.set(true);
                                })
                                    as Box<dyn FnMut()>)
                                .as_ref()
                                .unchecked_ref(),
                                delay_ms as i32,
                            )
                            .ok();
                        show_timeout = timeout;
                    }
                } else {
                    set_is_visible.set(true);
                }
            }
        }
    };

    let handle_mouse_leave = move |_ev: web_sys::MouseEvent| {
        // Clear timeout if exists
        if let (Some(window), Some(timeout_id)) = (web_sys::window(), show_timeout) {
            window.clear_timeout_with_handle(timeout_id);
        }
        set_is_visible.set(false);
    };

    // Store props in signals for reactive access
    let example_stored = StoredValue::new(example);
    let docs_link_stored = StoredValue::new(docs_link);

    view! {
        <div
            class="tooltip-trigger"
            style="display: inline-block; position: relative;"
            on:mouseenter=handle_mouse_enter
            on:mouseleave=handle_mouse_leave
        >
            {children()}

            <Show when=move || is_visible.get()>
                <div
                    class="contextual-tooltip"
                    style=move || {
                        let (x, y) = tooltip_position.get();
                        format!(
                            "position: fixed; left: {}px; top: {}px; z-index: 10000; background: #1f2937; color: white; padding: 16px; border-radius: 8px; box-shadow: 0 10px 25px rgba(0,0,0,0.3); max-width: 320px; font-size: 0.9rem; line-height: 1.5;",
                            x, y
                        )
                    }
                >
                    // Arrow
                    <div
                        class="tooltip-arrow"
                        style=move || {
                            match actual_position.get() {
                                TooltipPosition::Top => "position: absolute; bottom: -8px; left: 20px; width: 0; height: 0; border-left: 8px solid transparent; border-right: 8px solid transparent; border-top: 8px solid #1f2937;",
                                TooltipPosition::Bottom => "position: absolute; top: -8px; left: 20px; width: 0; height: 0; border-left: 8px solid transparent; border-right: 8px solid transparent; border-bottom: 8px solid #1f2937;",
                                TooltipPosition::Left => "position: absolute; right: -8px; top: 20px; width: 0; height: 0; border-top: 8px solid transparent; border-bottom: 8px solid transparent; border-left: 8px solid #1f2937;",
                                TooltipPosition::Right => "position: absolute; left: -8px; top: 20px; width: 0; height: 0; border-top: 8px solid transparent; border-bottom: 8px solid transparent; border-right: 8px solid #1f2937;",
                                TooltipPosition::Auto => "",
                            }
                        }
                    />

                    // Main content
                    <div style="margin-bottom: 12px;">
                        {content.clone()}
                    </div>

                    // Example section
                    <Show when=move || example_stored.get_value().is_some()>
                        <div style="background: #374151; padding: 10px; border-radius: 4px; margin-bottom: 12px; border-left: 3px solid #3b82f6;">
                            <div style="font-weight: 600; margin-bottom: 6px; color: #93c5fd; font-size: 0.8rem;">
                                "Example:"
                            </div>
                            <code style="color: #d1d5db; font-size: 0.85rem; font-family: monospace;">
                                {example_stored.get_value().unwrap_or_default()}
                            </code>
                        </div>
                    </Show>

                    // Documentation link
                    <Show when=move || docs_link_stored.get_value().is_some()>
                        <a
                            href={docs_link_stored.get_value().unwrap_or_default()}
                            target="_blank"
                            style="display: inline-flex; align-items: center; gap: 6px; color: #60a5fa; text-decoration: none; font-weight: 500; font-size: 0.85rem;"
                        >
                            <span>"📖"</span>
                            <span>"Learn more"</span>
                            <span style="font-size: 0.7rem;">"↗"</span>
                        </a>
                    </Show>
                </div>
            </Show>
        </div>
    }
}

/// Simplified tooltip for icons and buttons
#[component]
pub fn SimpleTooltip(
    #[prop(into)] text: String,
    #[prop(into, optional)] position: Option<TooltipPosition>,
    children: Children,
) -> impl IntoView {
    let (is_visible, set_is_visible) = signal(false);

    view! {
        <div
            class="simple-tooltip-trigger"
            style="display: inline-block; position: relative;"
            on:mouseenter=move |_| set_is_visible.set(true)
            on:mouseleave=move |_| set_is_visible.set(false)
        >
            {children()}

            <Show when=move || is_visible.get()>
                <div
                    class="simple-tooltip"
                    style=move || {
                        let pos = position.unwrap_or(TooltipPosition::Top);
                        let base = "position: absolute; z-index: 10000; background: #1f2937; color: white; padding: 6px 12px; border-radius: 4px; font-size: 0.8rem; white-space: nowrap; box-shadow: 0 4px 12px rgba(0,0,0,0.2);";
                        match pos {
                            TooltipPosition::Top => format!("{} bottom: calc(100% + 8px); left: 50%; transform: translateX(-50%);", base),
                            TooltipPosition::Bottom => format!("{} top: calc(100% + 8px); left: 50%; transform: translateX(-50%);", base),
                            TooltipPosition::Left => format!("{} right: calc(100% + 8px); top: 50%; transform: translateY(-50%);", base),
                            TooltipPosition::Right => format!("{} left: calc(100% + 8px); top: 50%; transform: translateY(-50%);", base),
                            TooltipPosition::Auto => format!("{} bottom: calc(100% + 8px); left: 50%; transform: translateX(-50%);", base),
                        }
                    }
                >
                    {text.clone()}
                </div>
            </Show>
        </div>
    }
}

/// Tooltip with rich content (HTML)
#[component]
pub fn RichTooltip(
    #[prop(into, optional)] position: Option<TooltipPosition>,
    /// Tooltip content (can include any Leptos view)
    tooltip_content: Box<dyn Fn() -> AnyView + Send + Sync>,
    /// Trigger element
    children: Children,
) -> impl IntoView {
    let (is_visible, set_is_visible) = signal(false);

    view! {
        <div
            class="rich-tooltip-trigger"
            style="display: inline-block; position: relative;"
            on:mouseenter=move |_| set_is_visible.set(true)
            on:mouseleave=move |_| set_is_visible.set(false)
        >
            {children()}

            <Show when=move || is_visible.get()>
                <div
                    class="rich-tooltip"
                    style=move || {
                        let pos = position.unwrap_or(TooltipPosition::Top);
                        let base = "position: absolute; z-index: 10000; background: white; padding: 16px; border-radius: 8px; box-shadow: 0 10px 25px rgba(0,0,0,0.15); min-width: 200px; max-width: 400px; border: 1px solid #e5e7eb;";
                        match pos {
                            TooltipPosition::Top => format!("{} bottom: calc(100% + 12px); left: 50%; transform: translateX(-50%);", base),
                            TooltipPosition::Bottom => format!("{} top: calc(100% + 12px); left: 50%; transform: translateX(-50%);", base),
                            TooltipPosition::Left => format!("{} right: calc(100% + 12px); top: 50%; transform: translateY(-50%);", base),
                            TooltipPosition::Right => format!("{} left: calc(100% + 12px); top: 50%; transform: translateY(-50%);", base),
                            TooltipPosition::Auto => format!("{} bottom: calc(100% + 12px); left: 50%; transform: translateX(-50%);", base),
                        }
                    }
                >
                    {tooltip_content()}
                </div>
            </Show>
        </div>
    }
}

/// Helper component to add tooltip to any element
#[component]
pub fn WithTooltip(
    #[prop(into)] tooltip: String,
    #[prop(optional)] docs_link: Option<String>,
    #[prop(optional)] example: Option<String>,
    children: Children,
) -> impl IntoView {
    view! {
        <ContextualTooltip
            content=tooltip
            docs_link=docs_link.unwrap_or_default()
            example=example.unwrap_or_default()
        >
            {children()}
        </ContextualTooltip>
    }
}
