use leptos_tiptap::TiptapEditorHandle;
use wasm_bindgen::{closure::Closure, JsCast};
use web_sys::window;

use crate::{
    editor_root_element, editor_runtime::dom_selection::node_is_within_root, EDITOR_STAGE_SELECTOR,
};

pub(crate) fn schedule_editor_focus(editor: TiptapEditorHandle) {
    let Some(win) = window() else {
        return;
    };
    let callback = Closure::<dyn FnMut()>::new(move || {
        let _ = editor.focus();
    });
    let _ = win.set_timeout_with_callback_and_timeout_and_arguments_0(
        callback.as_ref().unchecked_ref(),
        0,
    );
    callback.forget();
}

pub(crate) fn body_has_focus() -> bool {
    window()
        .and_then(|win| win.document())
        .and_then(|document| document.active_element())
        .map(|element| element.tag_name().eq_ignore_ascii_case("body"))
        .unwrap_or(false)
}

pub(crate) fn active_editor_stage() -> bool {
    let active_element_inside_stage = window()
        .and_then(|win| win.document())
        .and_then(|document| document.active_element())
        .and_then(|element| element.closest(EDITOR_STAGE_SELECTOR).ok().flatten())
        .is_some();

    if active_element_inside_stage {
        return true;
    }

    let Some(root) = editor_root_element() else {
        return false;
    };
    let Some(selection) = window().and_then(|win| win.get_selection().ok().flatten()) else {
        return false;
    };

    let anchor_inside = selection
        .anchor_node()
        .map(|node| node_is_within_root(node, &root))
        .unwrap_or(false);
    let focus_inside = selection
        .focus_node()
        .map(|node| node_is_within_root(node, &root))
        .unwrap_or(false);

    anchor_inside || focus_inside
}
