/**
 * Copyright (c) Meta Platforms, Inc. and affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @flow strict
 */

import type {LexicalCommand, LexicalEditor, NodeKey, TextNode} from 'lexical';
import * as React from 'react';

export type MenuTextMatch = {
  leadOffset: number,
  matchingString: string,
  replaceableString: string,
};

export type MenuResolution = {
  match?: MenuTextMatch,
  getRect: () => ClientRect,
};

export const PUNCTUATION: string =
  '\\.,\\+\\*\\?\\$\\@\\|#{}\\(\\)\\^\\-\\[\\]\\\\/!%\'"~=<>_:;';

declare export class MenuOption {
  key: string;
  ref: {current: HTMLElement | null};
  constructor(key: string): void;
  setRefElement(element: HTMLElement | null): void;
}

declare export var SCROLL_TYPEAHEAD_OPTION_INTO_VIEW_COMMAND: LexicalCommand<{
  index: number,
  option: MenuOption,
}>;

export type MenuRenderFn<TOption> = (
  anchorElementRef: {current: HTMLElement | null},
  itemProps: {
    selectedIndex: number | null,
    selectOptionAndCleanUp: (option: TOption) => void,
    setHighlightedIndex: (index: number) => void,
    options: Array<TOption>,
  },
  matchingString: string,
) => React.Portal | React.MixedElement | null;

declare export function getScrollParent(
  element: HTMLElement,
  includeHidden: boolean,
): HTMLElement | HTMLBodyElement;

declare export function useBasicTypeaheadTriggerMatch(
  trigger: string,
  options: {minLength?: number, maxLength?: number},
): TriggerFn;

export type TypeaheadMenuPluginProps<TOption> = {
  onQueryChange: (matchingString: string | null) => void,
  onSelectOption: (
    option: TOption,
    textNodeContainingQuery: TextNode | null,
    closeMenu: () => void,
    matchingString: string,
  ) => void,
  options: Array<TOption>,
  menuRenderFn: MenuRenderFn<TOption>,
  triggerFn: TriggerFn,
  onOpen?: (resolution: MenuResolution) => void,
  onClose?: () => void,
  anchorClassName?: string,
};

export type TriggerFn = (
  text: string,
  editor: LexicalEditor,
) => MenuTextMatch | null;

declare export function LexicalTypeaheadMenuPlugin<TOption>(
  options: TypeaheadMenuPluginProps<TOption>,
): React.MixedElement | null;