import {BridgeExtension} from '@10play/tentap-editor';
import Mention from '@tiptap/extension-mention';

type MentionEditorState = {
  mentionQuery?: string;
};

type MentionEditorInstance = {
  insertMention: () => void;
  setMention: (mention: {
    label: string;
    id: string;
    className?: string;
  }) => void;
};

export enum MentionMessageType {
  SetMention = 'SetMention',
  InsertMention = 'InsertMention',
}

declare module '@10play/tentap-editor' {
  interface BridgeState extends MentionEditorState {}
  interface EditorBridge extends MentionEditorInstance {}
}

type SuggestionQueryMessage = {
  type: MentionMessageType.SetMention;
  payload: {
    label: string;
    id: string;
    className?: string;
  };
};

type InsertMentionMessage = {
  type: MentionMessageType.InsertMention;
  payload: undefined;
};

type MentionEditorMessage = SuggestionQueryMessage | InsertMentionMessage;

export const MentionBridge = new BridgeExtension<
  MentionEditorState,
  MentionEditorInstance,
  MentionEditorMessage
>({
  onBridgeMessage(editor, message) {
    if (message.type === MentionMessageType.InsertMention) {
      const {selection} = editor.state;
      const tr = editor.state.tr;
      const dispatch = editor.view.dispatch;

      const position = selection.anchor;
      if (dispatch) {
        const currentChar = editor.state.doc
          .textBetween(selection.from - 1, selection.from)
          .at(-1);

        switch (currentChar) {
          case ' ':
            tr.insertText('@', position);
            break;
          case '@':
            tr.delete(selection.from - 1, selection.from);
            break;
          default:
            tr.insertText(' @', position);
            break;
        }
        dispatch(tr);
      }
      return true;
    }
    if (message.type === MentionMessageType.SetMention) {
      const state = editor.state;
      const {from, to} = editor.state.selection;
      const textBefore = state.doc.textBetween(0, from, ' ', ' ');
      const atIndex = textBefore.lastIndexOf('@');

      if (atIndex === -1) {
        return false; // No '@' found in the current selection
      }
      const mentionStart = from - (textBefore.length - atIndex);

      // Adjust the range to start from the '@' mark
      const nodeAfter = state.selection.$to.nodeAfter;
      const overrideSpace = nodeAfter?.text?.startsWith(' ');

      const range = {
        from: mentionStart,
        to: overrideSpace ? to + 1 : to,
      };

      if (overrideSpace) {
        editor.commands.insertContentAt(range, ' ');
      }
      editor
        .chain()
        .focus()
        .insertContentAt(range, [
          {
            type: Mention.name,
            attrs: message.payload,
          },
          {
            type: 'text',
            text: ' ',
          },
        ])
        .run();

      window.getSelection()?.collapseToEnd();
      return true;
    }
    return false;
  },
  // eslint-disable-next-line max-params
  extendEditorInstance(
    sendBridgeMessage,
    _webviewRef,
    _editorState,
    _setEditorState,
  ) {
    return {
      insertMention: () => {
        sendBridgeMessage({
          type: MentionMessageType.InsertMention,
          payload: undefined,
        });
      },
      setMention: payload => {
        sendBridgeMessage({
          type: MentionMessageType.SetMention,
          payload,
        });
      },
    };
  },
  extendEditorState(editor) {
    return {
      mentionQuery: editor.extensionStorage.mentionQuery,
    };
  },
});
