'use client';

/**
 * SlashMenu Component
 * 斜杠命令菜单组件
 */

import React, { useEffect, useRef, useState, useCallback, useMemo } from 'react';
import { useEditorStore } from '../../stores/useEditorStore';
import { cn } from '@/lib/utils';
import type { SlashMenuItem } from '../../core/types';
import { wrapInList } from 'prosemirror-schema-list';
import { setBlockType, wrapIn } from 'prosemirror-commands';
import {
  Heading1,
  Heading2,
  Heading3,
  List,
  ListOrdered,
  Quote,
  Code,
  Minus,
  Type,
} from 'lucide-react';
import { useTranslation } from '@/hooks/useTranslation';

interface SlashMenuProps {
  className?: string;
}

export function SlashMenu({ className }: SlashMenuProps) {
  const { t } = useTranslation();
  const {
    isSlashMenuOpen,
    slashMenuPosition,
    slashMenuQuery,
    slashMenuItems: storeItems,
    closeSlashMenu,
    view,
  } = useEditorStore();

  const defaultMenuItems = useMemo<SlashMenuItem[]>(
    () => [
      {
        name: 'paragraph',
        title: t.documentEditor.slashMenu.items.paragraph.title,
        description: t.documentEditor.slashMenu.items.paragraph.description,
        icon: Type,
        keywords: ['paragraph', 'text', '正文', '段落'],
        group: 'basic',
        priority: 0,
        command: (state, dispatch) => {
          if (dispatch) {
            const { $from } = state.selection;
            const tr = state.tr.setBlockType($from.pos, $from.pos, state.schema.nodes.paragraph);
            dispatch(tr);
          }
          return true;
        },
      },
      {
        name: 'heading1',
        title: t.documentEditor.slashMenu.items.heading1.title,
        description: t.documentEditor.slashMenu.items.heading1.description,
        icon: Heading1,
        keywords: ['heading', 'h1', '标题', '一级'],
        group: 'headings',
        priority: 1,
        command: (state, dispatch) => {
          if (dispatch) {
            const { $from } = state.selection;
            const tr = state.tr.setBlockType(
              $from.pos,
              $from.pos,
              state.schema.nodes.heading,
              { level: 1 }
            );
            dispatch(tr);
          }
          return true;
        },
      },
      {
        name: 'heading2',
        title: t.documentEditor.slashMenu.items.heading2.title,
        description: t.documentEditor.slashMenu.items.heading2.description,
        icon: Heading2,
        keywords: ['heading', 'h2', '标题', '二级'],
        group: 'headings',
        priority: 2,
        command: (state, dispatch) => {
          if (dispatch) {
            const { $from } = state.selection;
            const tr = state.tr.setBlockType(
              $from.pos,
              $from.pos,
              state.schema.nodes.heading,
              { level: 2 }
            );
            dispatch(tr);
          }
          return true;
        },
      },
      {
        name: 'heading3',
        title: t.documentEditor.slashMenu.items.heading3.title,
        description: t.documentEditor.slashMenu.items.heading3.description,
        icon: Heading3,
        keywords: ['heading', 'h3', '标题', '三级'],
        group: 'headings',
        priority: 3,
        command: (state, dispatch) => {
          if (dispatch) {
            const { $from } = state.selection;
            const tr = state.tr.setBlockType(
              $from.pos,
              $from.pos,
              state.schema.nodes.heading,
              { level: 3 }
            );
            dispatch(tr);
          }
          return true;
        },
      },
      {
        name: 'bulletList',
        title: t.documentEditor.slashMenu.items.bulletList.title,
        description: t.documentEditor.slashMenu.items.bulletList.description,
        icon: List,
        keywords: ['bullet', 'list', 'ul', '列表', '无序'],
        group: 'lists',
        priority: 4,
        command: (state, dispatch) => {
          const bulletListType = state.schema.nodes.bulletList;
          if (!bulletListType) return false;
          return wrapInList(bulletListType)(state, dispatch);
        },
      },
      {
        name: 'orderedList',
        title: t.documentEditor.slashMenu.items.orderedList.title,
        description: t.documentEditor.slashMenu.items.orderedList.description,
        icon: ListOrdered,
        keywords: ['ordered', 'list', 'ol', '列表', '有序', '编号'],
        group: 'lists',
        priority: 5,
        command: (state, dispatch) => {
          const orderedListType = state.schema.nodes.orderedList;
          if (!orderedListType) return false;
          return wrapInList(orderedListType)(state, dispatch);
        },
      },
      {
        name: 'blockquote',
        title: t.documentEditor.slashMenu.items.blockquote.title,
        description: t.documentEditor.slashMenu.items.blockquote.description,
        icon: Quote,
        keywords: ['quote', 'blockquote', '引用'],
        group: 'blocks',
        priority: 6,
        command: (state, dispatch) => {
          const blockquoteType = state.schema.nodes.blockquote;
          if (!blockquoteType) return false;
          return wrapIn(blockquoteType)(state, dispatch);
        },
      },
      {
        name: 'codeBlock',
        title: t.documentEditor.slashMenu.items.codeBlock.title,
        description: t.documentEditor.slashMenu.items.codeBlock.description,
        icon: Code,
        keywords: ['code', 'codeblock', '代码'],
        group: 'blocks',
        priority: 7,
        command: (state, dispatch) => {
          const codeBlockType = state.schema.nodes.codeBlock;
          if (!codeBlockType) return false;
          return setBlockType(codeBlockType)(state, dispatch);
        },
      },
      {
        name: 'divider',
        title: t.documentEditor.slashMenu.items.divider.title,
        description: t.documentEditor.slashMenu.items.divider.description,
        icon: Minus,
        keywords: ['divider', 'hr', 'horizontal', '分割', '分隔'],
        group: 'blocks',
        priority: 8,
        command: (state, dispatch) => {
          const hrType = state.schema.nodes.horizontalRule;
          if (!hrType) return false;
          if (dispatch) {
            const { $from } = state.selection;
            const tr = state.tr.replaceSelectionWith(hrType.create());
            // 在分割线后插入段落
            const paragraphType = state.schema.nodes.paragraph;
            if (paragraphType) {
              tr.insert(tr.selection.from, paragraphType.create());
            }
            dispatch(tr.scrollIntoView());
          }
          return true;
        },
      },
    ],
    [t]
  );

  const menuLabelMap = useMemo(
    () => ({
      paragraph: t.documentEditor.slashMenu.items.paragraph,
      heading1: t.documentEditor.slashMenu.items.heading1,
      heading2: t.documentEditor.slashMenu.items.heading2,
      heading3: t.documentEditor.slashMenu.items.heading3,
      heading4: t.documentEditor.slashMenu.items.heading4,
      bulletList: t.documentEditor.slashMenu.items.bulletList,
      orderedList: t.documentEditor.slashMenu.items.orderedList,
      blockquote: t.documentEditor.slashMenu.items.blockquote,
      codeBlock: t.documentEditor.slashMenu.items.codeBlock,
      divider: t.documentEditor.slashMenu.items.divider,
      image: t.documentEditor.slashMenu.items.image,
      table: t.documentEditor.slashMenu.items.table,
      'callout-info': t.documentEditor.slashMenu.items.calloutInfo,
      'callout-warning': t.documentEditor.slashMenu.items.calloutWarning,
      'callout-success': t.documentEditor.slashMenu.items.calloutSuccess,
      'callout-error': t.documentEditor.slashMenu.items.calloutError,
    }),
    [t]
  );

  const getItemLabel = useCallback(
    (item: SlashMenuItem) => {
      const mapped = menuLabelMap[item.name as keyof typeof menuLabelMap];
      return {
        title: mapped?.title ?? item.title,
        description: mapped?.description ?? item.description,
      };
    },
    [menuLabelMap]
  );

  // 合并 store 中的扩展项和默认菜单项，扩展项优先
  const items = storeItems.length > 0
    ? [...storeItems, ...defaultMenuItems.filter(
        (d) => !storeItems.some((s) => s.name === d.name)
      )]
    : defaultMenuItems;
  const menuRef = useRef<HTMLDivElement>(null);
  const [selectedIndex, setSelectedIndex] = useState(0);

  // 过滤菜单项
  const filteredItems = items.filter((item) => {
    if (!slashMenuQuery) return true;
    const query = slashMenuQuery.toLowerCase();
    const { title } = getItemLabel(item);
    return (
      item.name.toLowerCase().includes(query) ||
      title.toLowerCase().includes(query) ||
      item.keywords?.some((k) => k.toLowerCase().includes(query))
    );
  });

  // 重置选中索引
  useEffect(() => {
    setSelectedIndex(0);
  }, [slashMenuQuery]);

  // 执行命令
  const executeCommand = useCallback(
    (item: SlashMenuItem) => {
      if (!view) return;

      const { state, dispatch } = view;

      // 删除 / 和查询文本
      const { from } = state.selection;
      const textBefore = state.doc.textBetween(
        Math.max(0, from - slashMenuQuery.length - 1),
        from
      );
      const slashPos = textBefore.lastIndexOf('/');
      if (slashPos !== -1) {
        const deleteFrom = from - slashMenuQuery.length - 1;
        const tr = state.tr.delete(deleteFrom, from);
        dispatch(tr);
      }

      // 执行命令
      const newState = view.state;
      item.command(newState, view.dispatch);

      closeSlashMenu();
      view.focus();
    },
    [view, slashMenuQuery, closeSlashMenu]
  );

  // 键盘导航
  useEffect(() => {
    if (!isSlashMenuOpen) return;

    const handleKeyDown = (e: KeyboardEvent) => {
      switch (e.key) {
        case 'ArrowDown':
          e.preventDefault();
          setSelectedIndex((i) => (i + 1) % filteredItems.length);
          break;
        case 'ArrowUp':
          e.preventDefault();
          setSelectedIndex((i) => (i - 1 + filteredItems.length) % filteredItems.length);
          break;
        case 'Enter':
          e.preventDefault();
          if (filteredItems[selectedIndex]) {
            executeCommand(filteredItems[selectedIndex]);
          }
          break;
        case 'Escape':
          e.preventDefault();
          closeSlashMenu();
          view?.focus();
          break;
      }
    };

    document.addEventListener('keydown', handleKeyDown);
    return () => document.removeEventListener('keydown', handleKeyDown);
  }, [isSlashMenuOpen, filteredItems, selectedIndex, executeCommand, closeSlashMenu, view]);

  // 点击外部关闭
  useEffect(() => {
    if (!isSlashMenuOpen) return;

    const handleClickOutside = (e: MouseEvent) => {
      if (menuRef.current && !menuRef.current.contains(e.target as Node)) {
        closeSlashMenu();
      }
    };

    document.addEventListener('mousedown', handleClickOutside);
    return () => document.removeEventListener('mousedown', handleClickOutside);
  }, [isSlashMenuOpen, closeSlashMenu]);

  if (!isSlashMenuOpen || !slashMenuPosition) return null;

  return (
    <div
      ref={menuRef}
      className={cn(
        'slash-menu',
        'fixed z-50 w-72 rounded-lg border border-gray-200 bg-white py-2 shadow-lg',
        className
      )}
      style={{
        top: slashMenuPosition.top,
        left: slashMenuPosition.left,
      }}
    >
      {filteredItems.length === 0 ? (
        <div className="px-4 py-3 text-sm text-gray-500">
          {t.documentEditor.slashMenu.noResults}
        </div>
      ) : (
        <div className="max-h-80 overflow-y-auto">
          {filteredItems.map((item, index) => {
            const Icon = item.icon;
            const { title, description } = getItemLabel(item);
            return (
              <button
                key={item.name}
                type="button"
                className={cn(
                  'flex w-full items-center gap-3 px-4 py-2 text-left transition-colors',
                  index === selectedIndex
                    ? 'bg-blue-50 text-blue-700'
                    : 'text-gray-700 hover:bg-gray-50'
                )}
                onClick={() => executeCommand(item)}
                onMouseEnter={() => setSelectedIndex(index)}
              >
                {Icon && (
                  <div
                    className={cn(
                      'flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-md border',
                      index === selectedIndex
                        ? 'border-blue-200 bg-blue-100'
                        : 'border-gray-200 bg-gray-50'
                    )}
                  >
                    <Icon className="h-5 w-5" />
                  </div>
                )}
                <div className="min-w-0 flex-1">
                  <div className="text-sm font-medium">{title}</div>
                  {description && (
                    <div className="truncate text-xs text-gray-500">{description}</div>
                  )}
                </div>
              </button>
            );
          })}
        </div>
      )}
    </div>
  );
}

export default SlashMenu;
