import { Extension, type Editor, type Range } from "@tiptap/core";
import Suggestion, { type SuggestionProps } from "@tiptap/suggestion";
import { ReactRenderer } from "@tiptap/react";
import tippy, { type Instance as TippyInstance } from "tippy.js";
import { CommandList, type CommandItem } from "./command-list";
import {
    Heading1,
    Heading2,
    Heading3,
    Heading4,
    Heading5,
    Heading6,
    List,
    ListOrdered,
    Quote,
    Code,
    CheckSquare,
    Minus,
    Info,
    Type,
    Bold,
    Italic,
    Underline as UnderlineIcon,
    Strikethrough,
    Highlighter,
} from "lucide-react";

type CommandContext = { editor: Editor; range: Range };

function run(editor: Editor, range: Range, action: (ctx: CommandContext) => void) {
    action({ editor, range });
}

export const SlashCommand = Extension.create({
    name: "slashCommand",

    addOptions() {
        return {
            suggestion: {
                char: "/",
                startOfLine: false,
                allowedPrefixes: [" ", "\t", "\n"],
                command: ({ editor, range, props }: { editor: Editor; range: Range; props: CommandItem }) => {
                    props.command({ editor, range });
                },
            },
        };
    },

    addProseMirrorPlugins() {
        return [
            Suggestion({
                editor: this.editor,
                ...this.options.suggestion,
            }),
        ];
    },
});

export const getSuggestionItems = ({ query }: { query: string }): CommandItem[] => {
    const items: CommandItem[] = [
        {
            title: "一级标题",
            description: "大标题",
            group: "基础",
            icon: <Heading1 size={16} />,
            shortcut: "Ctrl+Alt+1",
            command: ({ editor, range }) => {
                run(editor, range, ({ editor, range }) => {
                    editor.chain().focus().deleteRange(range).setNode("heading", { level: 1 }).run();
                });
            },
        },
        {
            title: "二级标题",
            description: "中标题",
            group: "基础",
            icon: <Heading2 size={16} />,
            shortcut: "Ctrl+Alt+2",
            command: ({ editor, range }) => {
                run(editor, range, ({ editor, range }) => {
                    editor.chain().focus().deleteRange(range).setNode("heading", { level: 2 }).run();
                });
            },
        },
        {
            title: "三级标题",
            description: "小标题",
            group: "基础",
            icon: <Heading3 size={16} />,
            shortcut: "Ctrl+Alt+3",
            command: ({ editor, range }) => {
                run(editor, range, ({ editor, range }) => {
                    editor.chain().focus().deleteRange(range).setNode("heading", { level: 3 }).run();
                });
            },
        },
        {
            title: "正文",
            description: "普通段落",
            group: "基础",
            icon: <Type size={16} />,
            command: ({ editor, range }) => {
                run(editor, range, ({ editor, range }) => {
                    editor.chain().focus().deleteRange(range).setParagraph().run();
                });
            },
        },
        {
            title: "无序列表",
            description: "项目符号列表",
            group: "列表",
            icon: <List size={16} />,
            shortcut: "-",
            command: ({ editor, range }) => {
                run(editor, range, ({ editor, range }) => {
                    editor.chain().focus().deleteRange(range).toggleBulletList().run();
                });
            },
        },
        {
            title: "有序列表",
            description: "编号列表",
            group: "列表",
            icon: <ListOrdered size={16} />,
            shortcut: "1.",
            command: ({ editor, range }) => {
                run(editor, range, ({ editor, range }) => {
                    editor.chain().focus().deleteRange(range).toggleOrderedList().run();
                });
            },
        },
        {
            title: "任务列表",
            description: "待办事项",
            group: "列表",
            icon: <CheckSquare size={16} />,
            shortcut: "Ctrl+L",
            command: ({ editor, range }) => {
                run(editor, range, ({ editor, range }) => {
                    editor.chain().focus().deleteRange(range).toggleTaskList().run();
                });
            },
        },
        {
            title: "引用",
            description: "引用块",
            group: "列表",
            icon: <Quote size={16} />,
            shortcut: ">",
            command: ({ editor, range }) => {
                run(editor, range, ({ editor, range }) => {
                    editor.chain().focus().deleteRange(range).setBlockquote().run();
                });
            },
        },
        {
            title: "代码块",
            description: "插入代码段",
            group: "插入",
            icon: <Code size={16} />,
            shortcut: "```",
            command: ({ editor, range }) => {
                run(editor, range, ({ editor, range }) => {
                    editor.chain().focus().deleteRange(range).setCodeBlock().run();
                });
            },
        },
        {
            title: "分割线",
            description: "横线",
            group: "插入",
            icon: <Minus size={16} />,
            shortcut: "---",
            command: ({ editor, range }) => {
                run(editor, range, ({ editor, range }) => {
                    editor.chain().focus().deleteRange(range).setHorizontalRule().run();
                });
            },
        },
        {
            title: "高亮块（Callout）",
            description: "提示框",
            group: "插入",
            icon: <Info size={16} />,
            command: ({ editor, range }) => {
                run(editor, range, ({ editor, range }) => {
                    editor.chain().focus().deleteRange(range).setCallout().run();
                });
            },
        },
        {
            title: "表格",
            description: "插入 3x3 表格",
            group: "插入",
            icon: <div className="text-xs font-bold border rounded px-1">T</div>,
            command: ({ editor, range }) => {
                run(editor, range, ({ editor, range }) => {
                    editor.chain().focus().deleteRange(range).insertTable({ rows: 3, cols: 3, withHeaderRow: true }).run();
                });
            },
        },
        {
            title: "图片",
            description: "通过 URL 插入图片",
            group: "插入",
            icon: <div className="text-xs font-bold border rounded px-1">I</div>,
            command: ({ editor, range }) => {
                const url = window.prompt("图片 URL：");
                if (url) {
                    run(editor, range, ({ editor, range }) => {
                        editor.chain().focus().deleteRange(range).setImage({ src: url }).run();
                    });
                }
            },
        },
        {
            title: "YouTube",
            description: "嵌入视频",
            group: "插入",
            icon: <div className="text-xs font-bold border rounded px-1">Y</div>,
            command: ({ editor, range }) => {
                const url = window.prompt("YouTube URL：");
                if (url) {
                    run(editor, range, ({ editor, range }) => {
                        editor.chain().focus().deleteRange(range).setYoutubeVideo({ src: url }).run();
                    });
                }
            },
        },
        {
            title: "粗体",
            description: "加粗",
            group: "样式",
            icon: <Bold size={16} />,
            shortcut: "Ctrl+B",
            command: ({ editor, range }) => {
                run(editor, range, ({ editor, range }) => {
                    editor.chain().focus().deleteRange(range).toggleBold().run();
                });
            },
        },
        {
            title: "斜体",
            description: "倾斜",
            group: "样式",
            icon: <Italic size={16} />,
            shortcut: "Ctrl+I",
            command: ({ editor, range }) => {
                run(editor, range, ({ editor, range }) => {
                    editor.chain().focus().deleteRange(range).toggleItalic().run();
                });
            },
        },
        {
            title: "下划线",
            description: "下划线",
            group: "样式",
            icon: <UnderlineIcon size={16} />,
            shortcut: "Ctrl+U",
            command: ({ editor, range }) => {
                run(editor, range, ({ editor, range }) => {
                    editor.chain().focus().deleteRange(range).toggleUnderline().run();
                });
            },
        },
        {
            title: "删除线",
            description: "中划线",
            group: "样式",
            icon: <Strikethrough size={16} />,
            shortcut: "Ctrl+Shift+S",
            command: ({ editor, range }) => {
                run(editor, range, ({ editor, range }) => {
                    editor.chain().focus().deleteRange(range).toggleStrike().run();
                });
            },
        },
        {
            title: "高亮标记",
            description: "文本高亮",
            group: "样式",
            icon: <Highlighter size={16} />,
            shortcut: "Alt+D",
            command: ({ editor, range }) => {
                run(editor, range, ({ editor, range }) => {
                    editor.chain().focus().deleteRange(range).toggleHighlight().run();
                });
            },
        },
        {
            title: "四级标题",
            group: "基础",
            icon: <Heading4 size={16} />,
            shortcut: "Ctrl+Alt+4",
            command: ({ editor, range }) => {
                run(editor, range, ({ editor, range }) => {
                    editor.chain().focus().deleteRange(range).setNode("heading", { level: 4 }).run();
                });
            },
        },
        {
            title: "五级标题",
            group: "基础",
            icon: <Heading5 size={16} />,
            shortcut: "Ctrl+Alt+5",
            command: ({ editor, range }) => {
                run(editor, range, ({ editor, range }) => {
                    editor.chain().focus().deleteRange(range).setNode("heading", { level: 5 }).run();
                });
            },
        },
        {
            title: "六级标题",
            group: "基础",
            icon: <Heading6 size={16} />,
            shortcut: "Ctrl+Alt+6",
            command: ({ editor, range }) => {
                run(editor, range, ({ editor, range }) => {
                    editor.chain().focus().deleteRange(range).setNode("heading", { level: 6 }).run();
                });
            },
        },
    ];

    return items.filter((item) => item.title.toLowerCase().includes(query.toLowerCase()));
};

type CommandListHandle = {
    onKeyDown: (props: { event: KeyboardEvent }) => boolean;
};

export const renderSuggestionItems = () => {
    let component: ReactRenderer<CommandListHandle>;
    let popup: TippyInstance | null = null;

    return {
        onStart: (props: SuggestionProps<CommandItem>) => {
            component = new ReactRenderer(CommandList, {
                props,
                editor: props.editor,
            });

            if (!props.clientRect) {
                return;
            }

            popup = tippy(document.body, {
                getReferenceClientRect: () => props.clientRect?.() ?? new DOMRect(),
                appendTo: () => document.body,
                content: component.element,
                showOnCreate: true,
                interactive: true,
                trigger: "manual",
                placement: "bottom-start",
            });
        },

        onUpdate: (props: SuggestionProps<CommandItem>) => {
            component.updateProps(props);

            if (!props.clientRect || !popup) {
                return;
            }

            popup.setProps({
                getReferenceClientRect: () => props.clientRect?.() ?? new DOMRect(),
            });
        },

        onKeyDown: (props: { event: KeyboardEvent }) => {
            if (props.event.key === "Escape") {
                popup?.hide();
                return true;
            }

            return component.ref?.onKeyDown(props) ?? false;
        },

        onExit: () => {
            popup?.destroy();
            popup = null;
            component.destroy();
        },
    };
};
