use crate::{
    current_page_anchor_url, editor_block_by_id, request_ai_edit_bridge,
    write_mnote_text_to_clipboard,
};
use crate::editor_runtime::{
    block_hover_state::{BlockMenuLayout, HoveredBlockState},
    block_transform::{
        apply_text_align, run_block_turn_into_action, run_block_turn_into_folded_heading_action,
        run_block_turn_into_page_action, top_level_block_is_page, top_level_block_matches_action,
        top_level_block_range,
    },
    command_sync::{read_editor_snapshot, sync_persisted_editor_command},
    dom_events::trap_scroll_inside_menu,
    dom_selection::runtime_block_id_from_index,
    editor_focus::schedule_editor_focus,
    persistence::{persist_document_state, persisted_document_identity, PersistedDocumentIdentity},
    slash_actions::{SlashActionKind, SLASH_ACTIONS},
};
use leptos::prelude::*;
use leptos_tiptap::{TiptapEditorHandle, TiptapSelectionState, TiptapTextAlign};
use serde_json::Value;
use wasm_bindgen_futures::spawn_local;
use web_sys::{MouseEvent, WheelEvent};

#[derive(Clone, Copy)]
struct FoldedHeadingAction {
    level: u8,
    id: &'static str,
    icon: &'static str,
    label: &'static str,
}

const FOLDED_HEADING_ACTIONS: [FoldedHeadingAction; 4] = [
    FoldedHeadingAction {
        level: 1,
        id: "1",
        icon: "H1",
        label: "折叠主标题",
    },
    FoldedHeadingAction {
        level: 2,
        id: "2",
        icon: "H2",
        label: "折叠大标题",
    },
    FoldedHeadingAction {
        level: 3,
        id: "3",
        icon: "H3",
        label: "折叠中标题",
    },
    FoldedHeadingAction {
        level: 4,
        id: "4",
        icon: "H4",
        label: "折叠小标题",
    },
];

pub(crate) struct BlockHandleMenuViewProps {
    pub(crate) editor: TiptapEditorHandle,
    pub(crate) block: HoveredBlockState,
    pub(crate) duplicate_block_label: String,
    pub(crate) delete_block_label: String,
    pub(crate) menu_layout: BlockMenuLayout,
    pub(crate) signals: BlockHandleMenuSignals,
}

#[derive(Clone, Copy)]
pub(crate) struct BlockHandleMenuSignals {
    pub(crate) document_id: ReadSignal<Option<String>>,
    pub(crate) workspace_id: ReadSignal<Option<String>>,
    pub(crate) title: ReadSignal<String>,
    pub(crate) selection_state: ReadSignal<TiptapSelectionState>,
    pub(crate) block_turn_into_open: ReadSignal<bool>,
    pub(crate) block_folded_title_open: ReadSignal<bool>,
    pub(crate) set_ai_bridge_state: WriteSignal<String>,
    pub(crate) set_ai_bridge_message: WriteSignal<String>,
    pub(crate) set_dirty_count: WriteSignal<u32>,
    pub(crate) set_html_output: WriteSignal<String>,
    pub(crate) set_document_json: WriteSignal<Value>,
    pub(crate) set_json_output: WriteSignal<String>,
    pub(crate) set_command_feedback: WriteSignal<String>,
    pub(crate) set_block_menu_open: WriteSignal<bool>,
    pub(crate) set_block_menu_anchor: WriteSignal<Option<HoveredBlockState>>,
    pub(crate) set_block_turn_into_open: WriteSignal<bool>,
    pub(crate) set_block_folded_title_open: WriteSignal<bool>,
    pub(crate) set_hovered_block: WriteSignal<Option<HoveredBlockState>>,
}

fn runtime_persisted_identity(
    document_id: ReadSignal<Option<String>>,
    workspace_id: ReadSignal<Option<String>>,
) -> PersistedDocumentIdentity {
    persisted_document_identity(document_id.get_untracked(), workspace_id.get_untracked())
}

fn persist_block_transform_result(
    editor: TiptapEditorHandle,
    signals: BlockHandleMenuSignals,
) -> (String, Value, String) {
    let (html, snapshot, json_text) = read_editor_snapshot(editor);
    signals.set_dirty_count.update(|count| *count += 1);
    signals.set_html_output.set(html.clone());
    signals.set_document_json.set(snapshot.clone());
    signals.set_json_output.set(json_text.clone());
    (html, snapshot, json_text)
}

fn close_block_transform_menus(signals: BlockHandleMenuSignals) {
    signals.set_block_menu_open.set(false);
    signals.set_block_menu_anchor.set(None);
    signals.set_block_turn_into_open.set(false);
    signals.set_block_folded_title_open.set(false);
}

fn handle_turn_into_action_click(
    editor: TiptapEditorHandle,
    block_index: usize,
    kind: SlashActionKind,
    label: &'static str,
    signals: BlockHandleMenuSignals,
) {
    match run_block_turn_into_action(editor, block_index, kind) {
        Ok(message) => {
            close_block_transform_menus(signals);
            let (html, snapshot, _) = persist_block_transform_result(editor, signals);
            match persist_document_state(
                &runtime_persisted_identity(signals.document_id, signals.workspace_id),
                &signals.title.get_untracked(),
                &snapshot,
                Some(html),
            ) {
                Ok(()) => signals.set_command_feedback.set(format!(
                    "{}：块 -> {}，并已写入本地草稿",
                    message, label,
                )),
                Err(err) => signals.set_command_feedback.set(format!(
                    "{}：块 -> {}，但本地保存失败：{}",
                    message, label, err,
                )),
            }
        }
        Err(err) => signals.set_command_feedback.set(err),
    }
}

fn handle_folded_heading_click(
    editor: TiptapEditorHandle,
    block_index: usize,
    action: FoldedHeadingAction,
    signals: BlockHandleMenuSignals,
) {
    match run_block_turn_into_folded_heading_action(editor, block_index, action.level) {
        Ok(message) => {
            close_block_transform_menus(signals);
            let (html, snapshot, _) = persist_block_transform_result(editor, signals);
            match persist_document_state(
                &runtime_persisted_identity(signals.document_id, signals.workspace_id),
                &signals.title.get_untracked(),
                &snapshot,
                Some(html),
            ) {
                Ok(()) => signals
                    .set_command_feedback
                    .set(format!("{}，并已写入本地草稿", message)),
                Err(err) => signals
                    .set_command_feedback
                    .set(format!("{}，但本地保存失败：{}", message, err)),
            }
        }
        Err(err) => signals.set_command_feedback.set(err),
    }
}

fn block_transform_shortcut(
    editor: TiptapEditorHandle,
    block_index: usize,
    kind: SlashActionKind,
) -> &'static str {
    if top_level_block_matches_action(editor, block_index, kind) {
        return "✓";
    }

    match kind {
        SlashActionKind::Paragraph => "Ctrl+Alt+0",
        SlashActionKind::Todo => "Ctrl+Shift+5",
        SlashActionKind::Heading1 => "Ctrl+Shift+1",
        SlashActionKind::Heading2 => "Ctrl+Shift+2",
        SlashActionKind::Heading3 => "Ctrl+Shift+3",
        SlashActionKind::BulletList => "Ctrl+Shift+6",
        SlashActionKind::OrderedList => "Ctrl+Shift+7",
        SlashActionKind::CodeBlock => "Ctrl+Alt+-",
        SlashActionKind::Mindmap => "/dt",
        _ => "",
    }
}

fn block_transform_submenu_view(
    editor: TiptapEditorHandle,
    block_index: usize,
    signals: BlockHandleMenuSignals,
) -> impl IntoView {
    let current_block_is_page = top_level_block_is_page(editor, block_index);
    let page_current_marker = if current_block_is_page {
        "✓"
    } else {
        "Ctrl+Shift+9"
    };

    view! {
        <div class="block-drag-submenu" data-testid="block-transform-submenu" data-e30-testid="block-turn-into-menu">
            {SLASH_ACTIONS
                .iter()
                .filter(|action| {
                    !matches!(
                        action.kind,
                        SlashActionKind::Divider
                            | SlashActionKind::SimpleTable
                            | SlashActionKind::Image
                            | SlashActionKind::UploadAttachment
                            | SlashActionKind::Toc
                            | SlashActionKind::AiAssistant
                            | SlashActionKind::AiWrite
                            | SlashActionKind::ContinueWriting
                            | SlashActionKind::Summarize
                            | SlashActionKind::MoreAi
                    )
                })
                .map(|action| {
                    let kind = action.kind;
                    let label = action.label;
                    let icon = action.icon;
                    let is_current = top_level_block_matches_action(editor, block_index, kind);
                    let shortcut = block_transform_shortcut(editor, block_index, kind);
                    let testid = format!("block-transform-item-{}", action.id);
                    view! {
                        <button
                            class="block-drag-menu-item"
                            data-testid=testid
                            data-current=is_current.to_string()
                            on:click=move |event: MouseEvent| {
                                event.stop_propagation();
                                handle_turn_into_action_click(editor, block_index, kind, label, signals);
                            }
                        >
                            <span class="block-drag-menu-icon">{icon}</span>
                            <span>{label}</span>
                            <span class="block-drag-menu-shortcut">{shortcut}</span>
                        </button>
                    }
                })
                .collect_view()}
            <button
                class="block-drag-menu-item"
                data-testid="block-transform-item-page"
                data-current=current_block_is_page.to_string()
                on:click=move |event: MouseEvent| {
                    event.stop_propagation();
                    run_block_turn_into_page_action(
                        editor,
                        block_index,
                        signals.document_id,
                        signals.workspace_id,
                        signals.title,
                        signals.set_dirty_count,
                        signals.set_html_output,
                        signals.set_document_json,
                        signals.set_json_output,
                        signals.set_command_feedback,
                        signals.set_block_menu_open,
                        signals.set_block_menu_anchor,
                        signals.set_block_turn_into_open,
                    );
                }
            >
                <span class="block-drag-menu-icon">"▣"</span>
                <span>"页面"</span>
                <span class="block-drag-menu-shortcut">{page_current_marker}</span>
            </button>
            <button class="block-drag-menu-item" data-testid="block-transform-item-folded-list" disabled=true>
                <span class="block-drag-menu-icon">"≡"</span>
                <span>"折叠列表"</span>
                <span class="block-drag-menu-shortcut">"Ctrl+Shift+8"</span>
            </button>
            <button
                class="block-drag-menu-item"
                data-testid="block-transform-item-folded-title"
                on:mouseenter=move |_| {
                    signals.set_block_folded_title_open.set(true);
                }
                on:click=move |event: MouseEvent| {
                    event.stop_propagation();
                    signals.set_block_folded_title_open.set(true);
                }
            >
                <span class="block-drag-menu-icon">"H1"</span>
                <span>"折叠标题"</span>
                <span class="block-drag-menu-arrow">"›"</span>
            </button>
            <button class="block-drag-menu-item" data-testid="block-transform-item-folded-todo" disabled=true>
                <span class="block-drag-menu-icon">"☑"</span>
                <span>"折叠待办"</span>
                <span class="block-drag-menu-arrow">"›"</span>
            </button>
            <button class="block-drag-menu-item" data-testid="block-transform-item-emphasis" disabled=true>
                <span class="block-drag-menu-icon">"Aa"</span>
                <span>"着重文字"</span>
            </button>
            <button class="block-drag-menu-item" data-testid="block-transform-item-math" disabled=true>
                <span class="block-drag-menu-icon">"f(x)"</span>
                <span>"数学公式"</span>
                <span class="block-drag-menu-shortcut">"Ctrl+Alt++"</span>
            </button>
            {move || {
                if signals.block_folded_title_open.get() {
                    view! {
                        <div class="block-drag-tertiary-submenu" data-testid="block-transform-folded-title-submenu">
                            {FOLDED_HEADING_ACTIONS
                                .iter()
                                .map(|folded| {
                                    let action = *folded;
                                    let testid = format!("block-transform-folded-heading-{}", action.id);
                                    view! {
                                        <button
                                            class="block-drag-menu-item"
                                            data-testid=testid
                                            on:click=move |event: MouseEvent| {
                                                event.stop_propagation();
                                                handle_folded_heading_click(editor, block_index, action, signals);
                                            }
                                        >
                                            <span class="block-drag-menu-icon">{action.icon}</span>
                                            <span>{action.label}</span>
                                        </button>
                                    }
                                })
                                .collect_view()}
                        </div>
                    }.into_any()
                } else {
                    ().into_any()
                }
            }}
        </div>
    }
}

pub(crate) fn block_handle_menu_view(props: BlockHandleMenuViewProps) -> impl IntoView {
    let BlockHandleMenuViewProps {
        editor,
        block,
        duplicate_block_label,
        delete_block_label,
        menu_layout,
        signals,
    } = props;
    let block_index = block.index;
    let menu_top = format!("{}px", menu_layout.top);
    let menu_bottom = "auto";

    view! {
        <div
            class="block-drag-menu"
            data-testid="block-drag-menu"
            style:top=menu_top
            style:bottom=menu_bottom
            style:left=format!("{}px", menu_layout.left)
            style:max-height=format!("{}px", menu_layout.max_height)
            on:mousedown=move |event: MouseEvent| {
                event.stop_propagation();
            }
            on:mouseup=move |event: MouseEvent| {
                event.stop_propagation();
            }
            on:mousemove=move |event: MouseEvent| {
                event.stop_propagation();
            }
            on:click=move |event: MouseEvent| {
                event.stop_propagation();
            }
            on:wheel=move |event: WheelEvent| {
                trap_scroll_inside_menu(&event);
            }
        >
            <input
                class="block-drag-command-input"
                data-testid="block-drag-command-input"
                readonly=true
                placeholder="请输入指令"
            />
            <div class="block-drag-menu-actions">
                <div class="block-drag-menu-section">
                    <button
                        class="block-drag-menu-item"
                        data-testid="block-drag-menu-item-ai"
                        on:click=move |event: MouseEvent| {
                            event.stop_propagation();
                            request_ai_edit_bridge(
                                editor,
                                "ask_ai",
                                signals.document_id,
                                signals.workspace_id,
                                Some(block_index),
                                runtime_block_id_from_index(block_index),
                                signals.selection_state,
                                signals.set_ai_bridge_state,
                                signals.set_ai_bridge_message,
                                signals.set_dirty_count,
                                signals.set_html_output,
                                signals.set_document_json,
                                signals.set_json_output,
                                signals.title,
                                signals.set_command_feedback,
                            );
                        }
                    >
                        <span class="block-drag-menu-icon">"✦"</span>
                        <span>"AI 助理"</span>
                        <span class="block-drag-menu-shortcut">"Ctrl+J"</span>
                    </button>
                    <button
                        class="block-drag-menu-item"
                        data-testid="block-drag-menu-item-turn-into"
                        on:mouseenter=move |_| {
                            signals.set_block_turn_into_open.set(true);
                        }
                        on:click=move |event: MouseEvent| {
                            event.stop_propagation();
                            signals.set_block_turn_into_open.set(true);
                        }
                    >
                        <span class="block-drag-menu-icon">"↻"</span>
                        <span>"转换为"</span>
                        <span class="block-drag-menu-arrow">"›"</span>
                    </button>
                </div>
                <div class="block-drag-menu-divider"></div>
                <div class="block-drag-menu-section">
                    <button
                        class="block-drag-menu-item"
                        data-testid="block-drag-menu-item-duplicate"
                        on:click=move |event: MouseEvent| {
                            event.stop_propagation();
                            match crate::editor_runtime::history_safe_commands::duplicate_top_level_block_with_history(&editor, block_index) {
                                Ok(()) => {
                                    sync_persisted_editor_command(
                                        editor,
                                        &runtime_persisted_identity(signals.document_id, signals.workspace_id),
                                        signals.set_dirty_count,
                                        signals.set_html_output,
                                        signals.set_document_json,
                                        signals.set_json_output,
                                        signals.title,
                                        signals.set_command_feedback,
                                        format!("已复制 {}", duplicate_block_label.clone()),
                                    );
                                    signals.set_block_menu_open.set(false);
                                    signals.set_block_menu_anchor.set(None);
                                }
                                Err(err) => signals.set_command_feedback.set(err),
                            }
                        }
                    >
                        <span class="block-drag-menu-icon">"▣"</span>
                        <span>"拷贝副本"</span>
                        <span class="block-drag-menu-shortcut">"Ctrl+D"</span>
                    </button>
                    <button
                        class="block-drag-menu-item"
                        data-testid="block-drag-menu-item-delete"
                        on:mousedown=move |event: MouseEvent| {
                            event.prevent_default();
                            event.stop_propagation();
                        }
                        on:click=move |event: MouseEvent| {
                            event.stop_propagation();
                            match crate::editor_runtime::history_safe_commands::delete_top_level_block_with_history(&editor, block_index) {
                                Ok(()) => {
                                    sync_persisted_editor_command(
                                        editor,
                                        &runtime_persisted_identity(signals.document_id, signals.workspace_id),
                                        signals.set_dirty_count,
                                        signals.set_html_output,
                                        signals.set_document_json,
                                        signals.set_json_output,
                                        signals.title,
                                        signals.set_command_feedback,
                                        format!("已删除 {}", delete_block_label.clone()),
                                    );
                                    signals.set_block_menu_open.set(false);
                                    signals.set_block_menu_anchor.set(None);
                                    signals.set_hovered_block.set(None);
                                    schedule_editor_focus(editor);
                                }
                                Err(err) => signals.set_command_feedback.set(err),
                            }
                        }
                    >
                        <span class="block-drag-menu-icon">"⌫"</span>
                        <span>"删除"</span>
                        <span class="block-drag-menu-shortcut">"Del"</span>
                    </button>
                </div>
                <div class="block-drag-menu-divider"></div>
                <div class="block-drag-menu-section">
                    <button
                        class="block-drag-menu-item"
                        data-testid="block-drag-menu-item-copy-link"
                        on:click=move |event: MouseEvent| {
                            event.stop_propagation();
                            let Some(block_id) = runtime_block_id_from_index(block_index) else {
                                signals
                                    .set_command_feedback
                                    .set("当前块缺少 Rust block id，无法复制锚点链接".to_string());
                                return;
                            };
                            let Some(anchor_url) = current_page_anchor_url(&block_id) else {
                                signals
                                    .set_command_feedback
                                    .set("当前页面 URL 不可用，无法复制锚点链接".to_string());
                                return;
                            };
                            if let Some(block_element) = editor_block_by_id(&block_id) {
                                let _ = block_element.scroll_into_view_with_bool(true);
                            }
                            spawn_local(async move {
                                match write_mnote_text_to_clipboard(anchor_url.clone()).await {
                                    Ok(value) if value.as_bool().unwrap_or(false) => {
                                        signals.set_command_feedback.set(format!("已复制块链接：{}", block_id));
                                    }
                                    _ => {
                                        signals
                                            .set_command_feedback
                                            .set(format!("块链接已生成但剪贴板写入失败：{}", anchor_url));
                                    }
                                }
                            });
                        }
                    >
                        <span class="block-drag-menu-icon">"🔗"</span>
                        <span>"复制链接"</span>
                        <span class="block-drag-menu-arrow">"›"</span>
                    </button>
                    <button
                        class="block-drag-menu-item"
                        data-testid="block-drag-menu-item-move"
                        on:click=move |event: MouseEvent| {
                            event.stop_propagation();
                            signals
                                .set_command_feedback
                                .set("移动/嵌入流程后续接 Page Aggregate 命令".to_string());
                        }
                    >
                        <span class="block-drag-menu-icon">"↗"</span>
                        <span>"移动/嵌入到..."</span>
                        <span class="block-drag-menu-shortcut">"Alt+Shift+M/G"</span>
                    </button>
                    <button
                        class="block-drag-menu-item"
                        data-testid="block-drag-menu-item-history"
                        on:click=move |event: MouseEvent| {
                            event.stop_propagation();
                            signals
                                .set_command_feedback
                                .set("块历史入口已记录，恢复流程后续接版本链路".to_string());
                        }
                    >
                        <span class="block-drag-menu-icon">"◴"</span>
                        <span>"块历史..."</span>
                    </button>
                    <button
                        class="block-drag-menu-item"
                        data-testid="block-drag-menu-item-comment"
                        on:click=move |event: MouseEvent| {
                            event.stop_propagation();
                            signals.set_command_feedback.set("评论入口已打开".to_string());
                        }
                    >
                        <span class="block-drag-menu-icon">"◉"</span>
                        <span>"评论"</span>
                        <span class="block-drag-menu-shortcut">"Ctrl+Alt+M"</span>
                    </button>
                    <button
                        class="block-drag-menu-item"
                        data-testid="block-drag-menu-item-color"
                        on:mouseenter=move |_| {
                            signals
                                .set_command_feedback
                                .set("颜色子菜单后续按 Wolai 继续补齐".to_string());
                        }
                        on:click=move |event: MouseEvent| {
                            event.stop_propagation();
                            signals
                                .set_command_feedback
                                .set("颜色子菜单后续按 Wolai 继续补齐".to_string());
                        }
                    >
                        <span class="block-drag-menu-icon">"▧"</span>
                        <span>"颜色"</span>
                        <span class="block-drag-menu-arrow">"›"</span>
                    </button>
                    <button
                        class="block-drag-menu-item"
                        data-testid="block-drag-menu-item-align-center"
                        on:click=move |event: MouseEvent| {
                            event.stop_propagation();
                            let result = (|| -> Result<(), String> {
                                let document = editor
                                    .get_json()
                                    .map_err(|err| format!("读取当前 JSON 失败：{err}"))?;
                                let range = top_level_block_range(&document, block_index)
                                    .ok_or_else(|| format!("找不到第 {} 个块的选择范围", block_index + 1))?;
                                editor
                                    .set_text_selection(range)
                                    .map_err(|err| format!("选中当前块失败：{err}"))?;
                                apply_text_align(editor, TiptapTextAlign::Center)?;
                                let (html, snapshot, json_text) = read_editor_snapshot(editor);
                                signals.set_dirty_count.update(|count| *count += 1);
                                signals.set_html_output.set(html.clone());
                                signals.set_document_json.set(snapshot.clone());
                                signals.set_json_output.set(json_text);
                                persist_document_state(
                                    &runtime_persisted_identity(signals.document_id, signals.workspace_id),
                                    &signals.title.get_untracked(),
                                    &snapshot,
                                    Some(html),
                                )
                                .map_err(|err| format!("文字居中已执行，但本地保存失败：{err}"))?;
                                Ok(())
                            })();
                            match result {
                                Ok(()) => signals
                                    .set_command_feedback
                                    .set("已切到居中，并已写入本地草稿".to_string()),
                                Err(err) => signals.set_command_feedback.set(err),
                            }
                        }
                    >
                        <span class="block-drag-menu-icon">"≡"</span>
                        <span>"文字居中"</span>
                        <span class="block-drag-menu-switch"></span>
                    </button>
                    <button class="block-drag-menu-item" data-testid="block-drag-menu-item-translate" disabled=true>
                        <span class="block-drag-menu-icon">"文"</span>
                        <span>"文字翻译"</span>
                        <span class="block-drag-menu-arrow">"›"</span>
                    </button>
                    <button class="block-drag-menu-item" data-testid="block-drag-menu-item-poster" disabled=true>
                        <span class="block-drag-menu-icon">"▤"</span>
                        <span>"生成海报"</span>
                    </button>
                </div>
                <div class="block-drag-menu-footer" data-testid="block-drag-menu-footer">
                    <span>"anonymous"</span>
                    <span>"最后编辑于 刚刚"</span>
                </div>
                {move || {
                    if signals.block_turn_into_open.get() {
                        block_transform_submenu_view(editor, block_index, signals).into_any()
                    } else {
                        ().into_any()
                    }
                }}
            </div>
        </div>
    }
}
