import { Extension } from '@tiptap/core';
import { Plugin, PluginKey } from '@tiptap/pm/state';
import { Decoration, DecorationSet } from '@tiptap/pm/view';
import type { SlashCommand } from '@/lib/ai-providers';

declare module '@tiptap/core' {
  interface Commands<ReturnType> {
    slashCommands: {
      selectSlashCommand: (index: number) => ReturnType;
    };
  }
}

interface SlashCommandsOptions {
  commands: SlashCommand[];
  onSelectCommand: (command: SlashCommand) => void;
}

const slashCommandsPluginKey = new PluginKey('slashCommands');

export const SlashCommandsExtension = Extension.create<SlashCommandsOptions>({
  name: 'slashCommands',

  addOptions() {
    return {
      commands: [],
      onSelectCommand: () => {},
    };
  },

  addCommands() {
    return {
      selectSlashCommand: (index: number) => ({ editor }) => {
        const state = slashCommandsPluginKey.getState(editor.state);
        if (state && state.active && state.filteredCommands[index]) {
          const command = state.filteredCommands[index];
          
          // Clear the slash command
          const { from, to } = state.range;
          editor.chain()
            .deleteRange({ from, to })
            .focus()
            .run();
          
          // Execute the command
          this.options.onSelectCommand(command);
          
          return true;
        }
        return false;
      },
    };
  },

  addKeyboardShortcuts() {
    return {
      ArrowUp: ({ editor }) => {
        const state = slashCommandsPluginKey.getState(editor.state);
        if (state && state.active) {
          const newIndex = state.selectedIndex > 0 ? state.selectedIndex - 1 : state.filteredCommands.length - 1;
          editor.view.dispatch(
            editor.state.tr.setMeta(slashCommandsPluginKey, { selectedIndex: newIndex })
          );
          return true;
        }
        return false;
      },
      ArrowDown: ({ editor }) => {
        const state = slashCommandsPluginKey.getState(editor.state);
        if (state && state.active) {
          const newIndex = state.selectedIndex < state.filteredCommands.length - 1 ? state.selectedIndex + 1 : 0;
          editor.view.dispatch(
            editor.state.tr.setMeta(slashCommandsPluginKey, { selectedIndex: newIndex })
          );
          return true;
        }
        return false;
      },
      Enter: ({ editor }) => {
        const state = slashCommandsPluginKey.getState(editor.state);
        if (state && state.active) {
          editor.commands.selectSlashCommand(state.selectedIndex);
          return true;
        }
        return false;
      },
      Escape: ({ editor }) => {
        const state = slashCommandsPluginKey.getState(editor.state);
        if (state && state.active) {
          editor.view.dispatch(
            editor.state.tr.setMeta(slashCommandsPluginKey, { active: false })
          );
          return true;
        }
        return false;
      },
    };
  },

  addProseMirrorPlugins() {
    return [
      new Plugin({
        key: slashCommandsPluginKey,
        state: {
          init() {
            return {
              active: false,
              range: { from: 0, to: 0 },
              query: '',
              filteredCommands: [],
              selectedIndex: 0,
            };
          },
          apply(transaction, value, oldState, newState) {
            const meta = transaction.getMeta(slashCommandsPluginKey);
            if (meta) {
              return { ...value, ...meta };
            }

            // Check for slash character
            const { selection } = newState;
            const { empty, $from } = selection;
            
            if (!empty) {
              return { ...value, active: false };
            }

            const textBefore = $from.parent.textBetween(
              Math.max(0, $from.parentOffset - 50),
              $from.parentOffset,
              null,
              '\ufffc'
            );

            const match = textBefore.match(/\/(\w*)$/);
            
            if (match) {
              const query = match[1].toLowerCase();
              const filteredCommands = this.options.commands.filter(cmd => 
                cmd.command.toLowerCase().includes(query) ||
                cmd.description.toLowerCase().includes(query)
              );

              return {
                active: true,
                range: {
                  from: $from.pos - match[0].length,
                  to: $from.pos,
                },
                query,
                filteredCommands,
                selectedIndex: 0,
              };
            }

            return { ...value, active: false };
          },
        },
        props: {
          decorations(state) {
            const pluginState = this.getState(state);
            if (!pluginState.active) {
              return DecorationSet.empty;
            }

            // Slash menu decoration
            const { from } = pluginState.range;
            const decoration = Decoration.widget(from, () => {
              const container = document.createElement('div');
              container.className = 'slash-commands-menu';

              pluginState.filteredCommands.forEach((cmd, index) => {
                const item = document.createElement('div');
                item.className = `slash-command-item ${index === pluginState.selectedIndex ? 'selected' : ''}`;
                
                if (cmd.icon) {
                  const iconWrapper = document.createElement('div');
                  iconWrapper.innerHTML = cmd.icon;
                  item.appendChild(iconWrapper);
                }
                
                const textWrapper = document.createElement('div');
                
                const commandName = document.createElement('div');
                commandName.className = 'command-name';
                commandName.textContent = `/${cmd.command}`;
                textWrapper.appendChild(commandName);
                
                const commandDesc = document.createElement('div');
                commandDesc.className = 'command-description';
                commandDesc.textContent = cmd.description;
                textWrapper.appendChild(commandDesc);
                
                item.appendChild(textWrapper);
                
                item.addEventListener('click', () => {
                  const editor = (state as any).editor;
                  editor.commands.selectSlashCommand(index);
                });
                
                container.appendChild(item);
              });

              if (pluginState.filteredCommands.length === 0) {
                const empty = document.createElement('div');
                empty.className = 'text-gray-500 p-3 text-sm';
                empty.textContent = 'No commands found';
                container.appendChild(empty);
              }

              return container;
            });

            return DecorationSet.create(state.doc, [decoration]);
          },
        },
      }),
    ];
  },
});