import { Editor } from '@tiptap/core';
import { useCallback, useEffect, useRef, useMemo } from 'react';
import type { BlockMenuItem, CommandItem } from '@features/block-editor/types';
import { useFrequentlyUsed } from '@features/block-editor/hooks/useFrequentlyUsed';
import resolveCommands from '@features/block-editor/hooks/resolveCommands';

interface UseBlockMenusOptions {
  blockMenus: BlockMenuItem[];
}

export interface UseBlockMenusResult {
  groups: BlockMenuItem[];
  getFilteredBlockMenus: ({ query, editor }: { query: string; editor: Editor }) => BlockMenuItem[];
}

export function useBlockMenus({ blockMenus }: UseBlockMenusOptions): UseBlockMenusResult {
  const { frequentlyUsed, recordUsage } = useFrequentlyUsed();
  const itemsRef = useRef<BlockMenuItem[]>([]);

  useEffect(() => {
    itemsRef.current = blockMenus ?? [];
  }, [blockMenus]);

  const getFilteredBlockMenus = useCallback(
    ({ query, editor }: { query: string; editor: Editor }): BlockMenuItem[] => {
      const currentItems = itemsRef.current;
      if (!currentItems || currentItems.length === 0) {
        return [];
      }
      const withFilteredCommands = currentItems.map((group: BlockMenuItem) => ({
        ...group,
        commands: group.commands
          .filter((item) => {
            const labelNormalized = item.label.toLowerCase().trim();
            const queryNormalized = query.toLowerCase().trim();
            if (item.aliases) {
              const aliases = item.aliases.map((alias) => alias.toLowerCase().trim());
              return (
                labelNormalized.includes(queryNormalized) || aliases.some((alias) => alias.includes(queryNormalized))
              );
            }
            return labelNormalized.includes(queryNormalized);
          })
          .filter((command) => {
            if (!command.shouldBeHidden) {
              return true;
            }
            return !command.shouldBeHidden(editor);
          }),
      }));
      const withoutEmptyGroups = withFilteredCommands.filter((group) => {
        if (group.commands.length > 0) {
          return true;
        }
        return false;
      });
      const withEnabledSettings = withoutEmptyGroups.map((group) => ({
        ...group,
        commands: group.commands.map((command) => ({
          ...command,
          isEnabled: true,
        })),
      }));

      const resolvedGroups = withEnabledSettings.map((group) => ({
        ...group,
        commands: resolveCommands(group.commands, recordUsage),
      }));

      // よく使うコマンドグループ
      if (frequentlyUsed.length > 0) {
        // ルックアップマップを作成（O(n)）
        const frequentlyUsedMap = new Map<string, number>();
        frequentlyUsed.forEach((f, index) => {
          const key = `${f.name}:${f.class ?? ''}`;
          frequentlyUsedMap.set(key, index);
        });

        const frequentlyUsedCommands: CommandItem[] = resolvedGroups
          .flatMap((group) => group.commands)
          .filter((cmd, index, self) => {
            // name と class の両方が一致するかチェック
            const key = `${cmd.name}:${cmd.class ?? ''}`;
            const isFrequentlyUsed = frequentlyUsedMap.has(key);
            // 重複除去（name と class の両方が一致するもの）
            const firstIndex = self.findIndex((c) => c.name === cmd.name && (c.class ?? '') === (cmd.class ?? ''));
            return isFrequentlyUsed && firstIndex === index;
          })
          .toSorted((a, b) => {
            const aKey = `${a.name}:${a.class ?? ''}`;
            const bKey = `${b.name}:${b.class ?? ''}`;
            const aIndex = frequentlyUsedMap.get(aKey) ?? Infinity;
            const bIndex = frequentlyUsedMap.get(bKey) ?? Infinity;
            return aIndex - bIndex;
          });

        if (frequentlyUsedCommands.length > 0) {
          const frequentlyUsedGroup: BlockMenuItem = {
            title: 'よく使うブロック',
            name: 'frequently-used',
            commands: frequentlyUsedCommands,
          };
          return [frequentlyUsedGroup, ...resolvedGroups];
        }
      }
      return resolvedGroups;
    },
    [recordUsage, frequentlyUsed]
  );
  return {
    groups: blockMenus ?? [],
    getFilteredBlockMenus,
  };
}

export function useFilteredCommands(menus: BlockMenuItem[], editor: Editor, currentPos: number): BlockMenuItem[] {
  return useMemo(() => {
    return menus
      .map((item) => {
        const filteredCommands = item.commands.filter((cmd: CommandItem) => !cmd.isDisabled(editor, currentPos));
        return {
          ...item,
          commands: filteredCommands,
        };
      })
      .filter((item) => item.commands.length > 0 && item.name !== 'frequently-used');
  }, [menus, editor, currentPos]);
}
