use leptos::ev;
use leptos::prelude::*;
#[cfg(target_arch = "wasm32")]
use wasm_bindgen::JsCast;
#[cfg(target_arch = "wasm32")]
use web_sys::{window, HtmlElement};

/// Get all focusable elements within a container
#[cfg(target_arch = "wasm32")]
fn get_focusable_elements(container: &HtmlElement) -> web_sys::NodeList {
    use web_sys::Element;

    // Query selector for focusable elements
    let selector = "a[href], button:not([disabled]), textarea:not([disabled]), \
                    input:not([disabled]), select:not([disabled]), \
                    [tabindex]:not([tabindex=\"-1\"])";

    // Cast to Element to use query_selector_all
    let element: &Element = container.as_ref();

    element.query_selector_all(selector).unwrap_or_else(|_| {
        // Return empty NodeList on error (create from document)
        window()
            .and_then(|w| w.document())
            .map(|d| {
                d.query_selector_all("no-match").unwrap_or_else(|_| {
                    // Ultimate fallback: empty result
                    d.create_document_fragment()
                        .query_selector_all("*")
                        .unwrap()
                })
            })
            .unwrap()
    })
}

#[component]
pub fn ModalClient(
    children: Children,
    on_close: Callback<ev::MouseEvent>,
    class: &'static str,
) -> impl IntoView {
    // Reference to modal container for focus trap
    let modal_ref = NodeRef::<leptos::html::Div>::new();
    // Scroll lock effect - disable body scroll when modal is mounted
    #[cfg(target_arch = "wasm32")]
    {
        Effect::new(move |_| {
            // Lock scroll
            if let Some(body) = window().and_then(|w| w.document()).and_then(|d| d.body()) {
                let original = body
                    .style()
                    .get_property_value("overflow")
                    .unwrap_or_default();
                let _ = body.style().set_property("overflow", "hidden");

                // Restore scroll on unmount (nesting is unavoidable for effect cleanup pattern)
                #[allow(clippy::excessive_nesting)]
                on_cleanup(move || {
                    if let Some(b) = window().and_then(|w| w.document()).and_then(|d| d.body()) {
                        let _ = b.style().set_property("overflow", &original);
                    }
                });
            }
        });
    }

    // Focus trap effect - focus first focusable element on mount
    #[cfg(target_arch = "wasm32")]
    {
        #[allow(clippy::excessive_nesting)]
        Effect::new(move |_| {
            if let Some(modal_el) = modal_ref.get() {
                let html_el: HtmlElement = modal_el.clone().into();

                // Focus first focusable element in modal
                if let Some(first_node) = get_focusable_elements(&html_el).get(0) {
                    if let Ok(el) = first_node.dyn_into::<HtmlElement>() {
                        let _ = el.focus();
                    }
                }
            }
        });
    }

    // Keyboard handler - Escape to close, Tab/Shift+Tab for focus trap
    let modal_ref_kbd = modal_ref;
    let handle_keydown = move |kev: ev::KeyboardEvent| {
        let key = kev.key();

        if key == "Escape" {
            #[cfg(target_arch = "wasm32")]
            {
                use web_sys::MouseEvent as WebMouseEvent;
                // Create synthetic MouseEvent for close callback
                if let Ok(synthetic_event) = WebMouseEvent::new("click") {
                    on_close.run(synthetic_event);
                }
            }
        } else if key == "Tab" {
            #[cfg(target_arch = "wasm32")]
            #[allow(clippy::excessive_nesting)]
            {
                // Focus trap: cycle Tab through focusable elements
                if let Some(modal_el) = modal_ref_kbd.get() {
                    let html_el: HtmlElement = modal_el.clone().into();
                    let focusables = get_focusable_elements(&html_el);

                    if focusables.length() > 0 {
                        let first = focusables.get(0);
                        let last = focusables.get(focusables.length() - 1);

                        if kev.shift_key() {
                            // Shift+Tab: if at first element, wrap to last
                            if let Some(active) = window()
                                .and_then(|w| w.document())
                                .and_then(|d| d.active_element())
                            {
                                if first.is_some() && active.is_same_node(first.as_ref()) {
                                    kev.prevent_default();
                                    if let Some(last_node) = last {
                                        if let Ok(el) = last_node.dyn_into::<HtmlElement>() {
                                            let _ = el.focus();
                                        }
                                    }
                                }
                            }
                        } else {
                            // Tab: if at last element, wrap to first
                            if let Some(active) = window()
                                .and_then(|w| w.document())
                                .and_then(|d| d.active_element())
                            {
                                if last.is_some() && active.is_same_node(last.as_ref()) {
                                    kev.prevent_default();
                                    if let Some(first_node) = first {
                                        if let Ok(el) = first_node.dyn_into::<HtmlElement>() {
                                            let _ = el.focus();
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    };

    view! {
        // Backdrop with fade-in animation
        <div
            node_ref=modal_ref
            class="fixed inset-0 bg-black/50 backdrop-blur-sm z-40 flex items-center justify-center p-4
                   animate-fadeIn"
            role="dialog"
            aria-modal="true"
            tabindex="-1"
            on:click=move |ev| {
                // Close on backdrop click (not on modal content click)
                let target = ev.target();
                let current_target = ev.current_target();
                if target == current_target {
                    on_close.run(ev);
                }
            }
            on:keydown=handle_keydown
        >
            // Modal content with scale-in animation
            <div
                class={format!(
                    "bg-white/10 backdrop-blur-md border border-white/20 rounded-xl shadow-2xl \
                     shadow-cyan-500/20 p-6 max-w-lg w-full max-h-[90vh] overflow-y-auto \
                     animate-scaleIn {}",
                    class
                )}
                role="document"
            >
                {children()}
            </div>
        </div>
    }
}
