"use client";

import { useCallback, useMemo } from "react";
import type { JSX } from "react";
import {
  SuggestionMenuController,
  getDefaultReactSlashMenuItems,
  type DefaultReactSuggestionItem,
} from "@blocknote/react";
import { filterSuggestionItems, type BlockNoteEditor } from "@blocknote/core";
import { useRouter } from "next/navigation";
import {
  FileImage,
  FilePlus2,
  FileVideo,
  ListTree,
  Music,
  Paperclip,
  PilcrowSquare,
  Play,
  Spline,
  Sparkles,
  SquareCheckBig,
  Table,
} from "lucide-react";
import type { CustomBlockSchema } from "../schema";
import { useImagePicker } from "@/components/media/image-picker-context";
import type { MediaKind, MediaSelection } from "@/types/media";
import { createOnlineTable } from "@/lib/online-table";

type Props = {
  editor: BlockNoteEditor<CustomBlockSchema>;
  currentDocumentId: string;
};

const matchKeywords = (query: string, aliases: string[]) => {
  const lower = query.trim().toLowerCase();
  if (!lower) return true;
  return aliases.some((alias) => alias.toLowerCase().includes(lower));
};

function insertOrUpdateBlockForSlashMenuCompat(
  editor: BlockNoteEditor<CustomBlockSchema>,
  partialBlock: unknown,
) {
  const cursor = editor.getTextCursorPosition();
  const referenceBlock = cursor?.block ?? editor.topLevelBlocks[editor.topLevelBlocks.length - 1];
  if (!referenceBlock) {
    return;
  }

  const nextType = (partialBlock as { type?: unknown })?.type;
  const shouldAppendParagraph = nextType === "mindmap";

  const content = Array.isArray(referenceBlock.content) ? referenceBlock.content : [];
  const text = content
    .map((node) => (node && typeof (node as { text?: unknown }).text === "string" ? (node as { text: string }).text : ""))
    .join("")
    .trim();

  const looksLikeSlashCommand = text === "" || text.startsWith("/");

  if (referenceBlock.type === "paragraph" && looksLikeSlashCommand) {
    // 兼容默认 slash menu 行为：将当前段落“就地替换”为目标块类型，避免插入后又被 slash 菜单逻辑清理掉
    editor.updateBlock(referenceBlock, partialBlock as never);
    if (shouldAppendParagraph) {
      const inserted = editor.insertBlocks(
        [{ type: "paragraph" } as never],
        referenceBlock,
        "after",
      );
      const paragraph = inserted[0];
      if (paragraph) {
        try {
          editor.setTextCursorPosition(paragraph, "start");
        } catch {
          // ignore
        }
      }
    }
    return;
  }

  if (shouldAppendParagraph) {
    const inserted = editor.insertBlocks(
      [partialBlock as never, { type: "paragraph" } as never],
      referenceBlock,
      "after",
    );
    const paragraph = inserted[1] ?? inserted[inserted.length - 1];
    if (paragraph) {
      try {
        editor.setTextCursorPosition(paragraph, "start");
      } catch {
        // ignore
      }
    }
    return;
  }

  editor.insertBlocks([partialBlock as never], referenceBlock, "after");
}

const GROUP_TRANSLATIONS: Record<string, string> = {
  "Headings": "标题",
  "Subheadings": "副标题",
  "Basic blocks": "基础块",
  "Advanced": "高级",
  "Media": "媒体",
  "Others": "其他",
};

const DEFAULT_ITEM_TRANSLATIONS: Record<
  string,
  { title?: string; subtext?: string; group?: string; aliases?: string[] }
> = {
  "Paragraph": { title: "正文", group: "基础块", aliases: ["zw", "paragraph", "body"] },
  "Heading 1": { title: "主标题", group: "标题", aliases: ["biaoti", "bt1"] },
  "Heading 2": { title: "大标题", group: "标题", aliases: ["biaoti", "bt2"] },
  "Heading 3": { title: "中标题", group: "标题", aliases: ["biaoti", "bt3"] },
  "Heading 4": { title: "小标题", group: "标题", aliases: ["biaoti", "bt4"] },
  "Heading 5": { title: "极小标题", group: "标题", aliases: ["biaoti", "bt5"] },
  "Heading 6": { title: "最小标题", group: "标题", aliases: ["biaoti", "bt6"] },
  "Toggle Heading 1": { title: "可折叠主标题", group: "标题", aliases: ["toggle", "zd1"] },
  "Toggle Heading 2": { title: "可折叠大标题", group: "标题", aliases: ["toggle", "zd2"] },
  "Toggle Heading 3": { title: "可折叠中标题", group: "标题", aliases: ["toggle", "zd3"] },
  "Quote": { title: "引用", group: "基础块", aliases: ["quote", "引用"] },
  "Toggle List": { title: "折叠列表", group: "基础块", aliases: ["toggle list", "zd"] },
  "Numbered List": { title: "数字列表", group: "基础块", aliases: ["ordered", "ol"] },
  "Bullet List": { title: "符号列表", group: "基础块", aliases: ["ul", "list"] },
  "Check List": { title: "任务列表", group: "基础块", aliases: ["todo", "checkbox"] },
  "Code Block": { title: "代码块", group: "基础块", aliases: ["code", "pre"] },
  "Table": { title: "表格", group: "高级", aliases: ["table", "biaoge"] },
  "Image": { title: "插入图片", group: "媒体", subtext: "上传或引用图片资源", aliases: ["tupian", "image", "tp"] },
  "Video": { title: "插入视频", group: "媒体", subtext: "上传或引用视频", aliases: ["shipin", "video", "sp"] },
  "Audio": { title: "插入音频", group: "媒体", subtext: "上传或引用音频", aliases: ["yinpin", "audio", "yp"] },
  "File": { title: "插入文件", group: "媒体", subtext: "上传附件并生成卡片", aliases: ["wenjian", "file", "wj"] },
  "Emoji": { title: "插入表情", group: "其他", aliases: ["emoji", "biaoqing"] },
  "Divider": { title: "分割线", group: "基础块", aliases: ["divider", "hr"] },
  "Page Break": { title: "分页符", group: "基础块", aliases: ["page", "break"] },
};

const MEDIA_ICONS: Record<MediaKind, JSX.Element> = {
  image: <FileImage className="h-4 w-4 text-[#2563eb]" />,
  video: <FileVideo className="h-4 w-4 text-[#f97316]" />,
  audio: <Music className="h-4 w-4 text-[#10b981]" />,
  file: <Paperclip className="h-4 w-4 text-[#0f172a]" />,
};

const HEADING_PRESETS = [
  {
    level: 1,
    title: "主标题",
    subtext: "适合页面名称/顶层章节",
    aliases: ["biaoti1", "h1", "level1"],
  },
  {
    level: 2,
    title: "大标题",
    subtext: "用于章节逻辑层",
    aliases: ["biaoti2", "h2", "level2"],
  },
  {
    level: 3,
    title: "中标题",
    subtext: "用于小节和段落",
    aliases: ["biaoti3", "h3", "level3"],
  },
  {
    level: 4,
    title: "小标题",
    subtext: "更细的结构说明",
    aliases: ["biaoti4", "h4", "level4"],
  },
  {
    level: 5,
    title: "极小标题",
    subtext: "适合脚注/补充说明",
    aliases: ["biaoti5", "h5", "level5"],
  },
];

const isHeadingDefaultItem = (item: DefaultReactSuggestionItem) => {
  const maybeKey = (item as { key?: string }).key ?? "";
  if (maybeKey && (maybeKey === "heading" || maybeKey.startsWith("heading_") || maybeKey.startsWith("toggle_heading"))) {
    return true;
  }
  const title = item.title ?? "";
  return title.includes("标题");
};

export const CustomSlashMenu = ({ editor, currentDocumentId }: Props) => {
  const defaultItems = useMemo(() => getDefaultReactSlashMenuItems(editor), [editor]);
  const router = useRouter();
  const { openPicker } = useImagePicker();

  const getItems = useCallback(
    async (query: string) => {
      // 注意：不要把 cursor/referenceBlock 在 getItems 阶段“捕获”后长期复用。
      // Slash 菜单打开后，BlockNote 会持续更新光标与块对象；若使用陈旧引用，
      // 可能出现插入块“瞬间出现又消失/不落库”的现象（尤其是插入自定义块时）。
      const createTableItem: DefaultReactSuggestionItem = {
        title: "在线表格",
        group: "高级",
        aliases: ["online table", "bg", "表格"],
        icon: <Table className="h-4 w-4 text-[#0f172a]" />,
        onItemClick: async () => {
          const documentId = currentDocumentId;
          try {
            const newTable = await createOnlineTable(documentId);
            insertOrUpdateBlockForSlashMenuCompat(editor, {
              type: "onlineTable",
              props: { tableId: newTable.id, title: newTable.title },
              content: [],
            });
            window.dispatchEvent(new CustomEvent("online-table-saved", { detail: { tableId: newTable.id } }));
          } catch (error) {
            console.error("Failed to create table:", error);
            // TODO: 插入错误提示块
          }
        },
      };

      const createMindmapItem: DefaultReactSuggestionItem = {
        title: "思维导图",
        group: "高级",
        subtext: "插入可编辑导图（带顶栏工具）",
        aliases: ["mindmap", "swdt", "导图"],
        icon: <Spline className="h-4 w-4 text-[#2563eb]" />,
        onItemClick: () => {
          insertOrUpdateBlockForSlashMenuCompat(editor, {
            type: "mindmap",
            props: { docId: currentDocumentId },
            content: [],
          });
        },
      };

      const createPageItem: DefaultReactSuggestionItem = {
        title: "嵌入页面",
        group: "嵌入",
        aliases: ["page", "ym", "子页面", "嵌入页面块"],
        icon: <FilePlus2 className="h-4 w-4 text-[#2563eb]" />,
        onItemClick: async () => {
          const cursor = editor.getTextCursorPosition();
          const cursorBlock = cursor?.block as any;
          const firstText =
            Array.isArray(cursorBlock?.content) && cursorBlock.content.length > 0
              ? (cursorBlock.content[0] as any)?.text
              : undefined;
          const response = await fetch("/api/documents/create-child", {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify({
              parentId: currentDocumentId,
              title: typeof firstText === "string" && firstText.trim() ? firstText : "未命名页面",
              blocks: cursorBlock ? [cursorBlock] : [],
            }),
          });

          if (!response.ok) return;
          const { pageId, title } = await response.json();
          insertOrUpdateBlockForSlashMenuCompat(editor, {
            type: "pageReference",
            props: { pageId, title, asChildPage: true },
            content: [],
          });
          router.refresh();
        },
      };

      const headingItems: DefaultReactSuggestionItem[] = HEADING_PRESETS.map((preset) => ({
        title: preset.title,
        group: "标题",
        subtext: preset.subtext,
        aliases: preset.aliases,
        icon: <PilcrowSquare className="h-4 w-4 text-[#0f172a]" />,
        onItemClick: () => {
          insertOrUpdateBlockForSlashMenuCompat(editor, {
            type: "heading",
            props: { level: preset.level },
            content: [],
          });
        },
      }));

      const foldHeading: DefaultReactSuggestionItem = {
        title: "折叠标题",
        group: "标题",
        aliases: ["toggle", "zd", "fold"],
        icon: <ListTree className="h-4 w-4 text-[#0f172a]" />,
        onItemClick: () => {
          insertOrUpdateBlockForSlashMenuCompat(editor, {
            type: "heading",
            props: { level: 2, isToggleable: true },
            content: [],
          });
        },
      };

      const advancedTodo: DefaultReactSuggestionItem = {
        title: "高级待办",
        group: "待办",
        subtext: "四态状态 · Alt 直接取消",
        aliases: ["gjdblb", "todopro", "gaoji", "todo+"],
        icon: <SquareCheckBig className="h-4 w-4 text-[#2563eb]" />,
        onItemClick: () => {
          insertOrUpdateBlockForSlashMenuCompat(editor, {
            type: "advancedTodo",
            props: { status: "todo" },
            content: [],
          });
        },
      };

      const progressMeter: DefaultReactSuggestionItem = {
        title: "进度条",
        group: "进度",
        subtext: "自动读取下方待办完成度",
        aliases: ["jdt", "progress", "jindu"],
        icon: <Sparkles className="h-4 w-4 text-[#f59e0b]" />,
        onItemClick: () => {
          insertOrUpdateBlockForSlashMenuCompat(editor, {
            type: "progressMeter",
            props: { percent: 0, auto: true },
            content: [],
          });
        },
      };

      const foldAdvancedTodo: DefaultReactSuggestionItem = {
        title: "折叠高级待办",
        group: "待办",
        aliases: ["zdgjdb", "foldtodo"],
        icon: <Play className="h-4 w-4 text-[#9f1239]" />,
        onItemClick: () => {
          insertOrUpdateBlockForSlashMenuCompat(editor, {
            type: "advancedTodo",
            props: { status: "todo" },
            content: [],
          });
        },
      };

      const customItems = [
        ...headingItems,
        foldHeading,
        createPageItem,
        createTableItem,
        createMindmapItem,
        advancedTodo,
        foldAdvancedTodo,
        progressMeter,
      ].filter((item) => matchKeywords(query, item.aliases ?? []));

      const insertMediaSelection = (selection: MediaSelection) => {
        insertOrUpdateBlockForSlashMenuCompat(editor, {
          type: "media",
          props: {
            fileUrl: selection.fileUrl,
            thumbnailUrl: selection.thumbnailUrl ?? selection.fileUrl,
            assetId: selection.assetId,
            assetType: selection.assetType ?? "image",
            fileName: selection.fileName ?? "",
            fileSize: selection.fileSize ?? null,
            mimeType: selection.mimeType ?? "",
            ocrStatus: "idle",
          },
          content: [],
        });
      };

      const handleMediaPick = (mediaType: MediaKind) => {
        openPicker({
          mediaType,
          multiple: true,
          onSelect: (selection) => {
            insertMediaSelection({
              ...selection,
              assetType: selection.assetType ?? mediaType,
            });
          },
        });
      };

      const localizedDefaults = defaultItems.map((item) => {
        const translation = DEFAULT_ITEM_TRANSLATIONS[item.title];
        const next: DefaultReactSuggestionItem = { ...item };
        if (translation?.title) next.title = translation.title;
        if (translation?.subtext) next.subtext = translation.subtext;
        if (translation?.aliases) next.aliases = translation.aliases;
        if (translation?.group) {
          next.group = translation.group;
        } else if (item.group && GROUP_TRANSLATIONS[item.group]) {
          next.group = GROUP_TRANSLATIONS[item.group];
        }

        if (["Image", "Video", "Audio", "File"].includes(item.title)) {
          const mediaType = item.title.toLowerCase() as MediaKind;
          next.icon = MEDIA_ICONS[mediaType];
          next.group = translation?.group ?? "媒体";
          next.subtext = translation?.subtext ?? next.subtext;
          next.aliases = translation?.aliases ?? next.aliases;
          next.onItemClick = () => handleMediaPick(mediaType);
        }
        return next;
      });

      const sanitizedDefaults = localizedDefaults.filter(
        (item) => !isHeadingDefaultItem(item) && item.title !== "表格",
      );
      const merged = [...customItems, ...sanitizedDefaults];
      return filterSuggestionItems(merged, query);
    },
    [currentDocumentId, defaultItems, editor, openPicker, router],
  );

  return <SuggestionMenuController triggerCharacter="/" getItems={getItems} />;
}
