/**
 * 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 {
  DOMConversionMap,
  EditorConfig,
  LexicalNode,
  NodeKey,
  RangeSelection,
  LexicalCommand,
  SerializedElementNode,
  LexicalEditor,
} from 'lexical';
import {addClassNamesToElement} from '@lexical/utils';
import {$isElementNode, ElementNode} from 'lexical';
import type {LexicalExtension, NamedSignalsOutput} from '@lexical/extension';

export type LinkAttributes = $ReadOnly<{
  rel?: null | string,
  target?: null | string,
  title?: null | string,
}>;
export type SerializedLinkNode = {
  ...SerializedElementNode,
  rel?: null | string,
  target?: null | string,
  title?: null | string,
  url: string,
  ...
};
declare export class LinkNode extends ElementNode {
  __url: string;
  __target: null | string;
  __rel: null | string;
  __title: null | string;
  static getType(): string;
  static clone(node: LinkNode): LinkNode;
  constructor(url: string, attributes?: LinkAttributes, key?: NodeKey): void;
  createDOM(config: EditorConfig): HTMLElement;
  static importDOM(): DOMConversionMap | null;
  exportJSON(): SerializedLinkNode;
  getURL(): string;
  setURL(url: string): void;
  getTarget(): null | string;
  setTarget(target: null | string): void;
  getRel(): null | string;
  setRel(rel: null | string): void;
  getTitle(): null | string;
  setTitle(title: null | string): void;
  insertNewAfter(
    selection: RangeSelection,
    restoreSelection?: boolean,
  ): null | ElementNode;
  canInsertTextBefore(): false;
  canInsertTextAfter(): false;
  canBeEmpty(): false;
  isInline(): true;
}
declare export function $createLinkNode(
  url: string,
  attributes?: LinkAttributes,
): LinkNode;
declare export function $isLinkNode(
  node: ?LexicalNode,
): node is LinkNode;
export type SerializedAutoLinkNode = {
  ...SerializedLinkNode,
  isUnlinked: boolean,
  ...
};
declare export class AutoLinkNode extends LinkNode {
  static getType(): string;
  // $FlowFixMe[incompatible-type] clone method inheritance
  static clone(node: AutoLinkNode): AutoLinkNode;
  insertNewAfter(
    selection: RangeSelection,
    restoreSelection?: boolean,
  ): null | ElementNode;
}
declare export function $createAutoLinkNode(
  url: string,
  attributes?: LinkAttributes,
): AutoLinkNode;
declare export function $isAutoLinkNode(
  node: ?LexicalNode,
): node is AutoLinkNode;

declare export var TOGGLE_LINK_COMMAND: LexicalCommand<
  string | {url: string, ...LinkAttributes} | null,
>;
declare export function $toggleLink(
  url: null | string,
  attributes: LinkAttributes,
): void;
/** @deprecated renamed to {@link $toggleLink} by @lexical/eslint-plugin rules-of-lexical */
declare const toggleLink: typeof $toggleLink;
declare export function formatUrl(url: string): string;

export type ClickableLinkConfig = {
  newTab: boolean;
  disabled: boolean;
}

type AddEventListenerOptions = Exclude<AddEventListenerOptionsOrUseCapture, boolean>;

declare export function registerClickableLink(
  editor: LexicalEditor,
  stores: NamedSignalsOutput<ClickableLinkConfig>,
  eventOptions?: Pick<AddEventListenerOptions, 'signal'>,
): () => void;

declare export var ClickableLinkExtension: LexicalExtension<ClickableLinkConfig, "@lexical/link/ClickableLink", NamedSignalsOutput<ClickableLinkConfig>, void>;
declare export function registerClickableLink(
  editor: LexicalEditor,
  stores: NamedSignalsOutput<ClickableLinkConfig>,
  eventOptions?: Pick<AddEventListenerOptions, 'signal'>,
): () => void;

export type AutoLinkConfig = {
  matchers: LinkMatcher[];
  changeHandlers: ChangeHandler[];
}

export type ChangeHandler = (
  url: string | null,
  prevUrl: string | null,
) => void;

export type AutoLinkAttributes = Partial<
  {...LinkAttributes, isUnlinked?: boolean}
>;

export type LinkMatcherResult = {
  attributes?: AutoLinkAttributes;
  index: number;
  length: number;
  text: string;
  url: string;
}

export type LinkMatcher = (text: string) => LinkMatcherResult | null;

declare export function createLinkMatcherWithRegExp(
  regExp: RegExp,
  urlTransformer?: (text: string) => string,
): LinkMatcher;

declare export var AutoLinkExtension: LexicalExtension<AutoLinkConfig, "@lexical/link/AutoLink", void, void>;

declare export function registerAutoLink(
  editor: LexicalEditor,
  config?: AutoLinkConfig,
): () => void;

export type LinkConfig = {
  validateUrl: void | ((url: string) => boolean);
  attributes: void | LinkAttributes;
}
declare export var LinkExtension: LexicalExtension<LinkConfig, "@lexical/link/Link", NamedSignalsOutput<LinkConfig>, void>;
declare export function registerLink(
  editor: LexicalEditor,
  stores: NamedSignalsOutput<LinkConfig>,
): () => void;
