import { Extension } from '@tiptap/core'

import type { FloatingMenuPluginProps } from './floating-menu-plugin.js'
import { FloatingMenuPlugin } from './floating-menu-plugin.js'

export type FloatingMenuOptions = Omit<FloatingMenuPluginProps, 'editor' | 'element'> & {
  /**
   * The DOM element that contains your menu.
   * @type {HTMLElement}
   * @default null
   */
  element: HTMLElement | null
}

declare module '@tiptap/core' {
  interface Commands<ReturnType> {
    floatingMenu: {
      /**
       * Update the position of the floating menu.
       * @example editor.commands.updateFloatingMenuPosition()
       */
      updateFloatingMenuPosition: () => ReturnType
    }
  }
}

/**
 * This extension allows you to create a floating menu.
 * @see https://tiptap.dev/api/extensions/floating-menu
 */
export const FloatingMenu = Extension.create<FloatingMenuOptions>({
  name: 'floatingMenu',

  addOptions() {
    return {
      element: null,
      options: {},
      pluginKey: 'floatingMenu',
      updateDelay: undefined,
      resizeDelay: undefined,
      appendTo: undefined,
      shouldShow: null,
    }
  },

  addCommands() {
    return {
      updateFloatingMenuPosition:
        () =>
        ({ tr, dispatch }) => {
          if (dispatch) {
            tr.setMeta(this.options.pluginKey, 'updatePosition')
          }
          return true
        },
    }
  },

  addProseMirrorPlugins() {
    if (!this.options.element) {
      return []
    }

    return [
      FloatingMenuPlugin({
        pluginKey: this.options.pluginKey,
        editor: this.editor,
        element: this.options.element,
        updateDelay: this.options.updateDelay,
        resizeDelay: this.options.resizeDelay,
        options: this.options.options,
        appendTo: this.options.appendTo,
        shouldShow: this.options.shouldShow,
      }),
    ]
  },
})
