// Adapted from: https://github.com/facebook/lexical/issues/2715#issuecomment-1209090485

import {
  BOLD_ITALIC_UNDERSCORE,
  BOLD_ITALIC_STAR,
  BOLD_STAR,
  BOLD_UNDERSCORE,
  STRIKETHROUGH,
  INLINE_CODE,
  HEADING,
  QUOTE,
  ORDERED_LIST,
  UNORDERED_LIST,
  LINK,
  TextMatchTransformer,
} from '@lexical/markdown';

const replaceEscapedChars = (text: string): string => {
  // convert "\*" to "*", "\_" to "_", "\~" to "~", ...
  return text
    .replaceAll('\\*', '*')
    .replaceAll('\\_', '_')
    .replaceAll('\\-', '-')
    .replaceAll('\\#', '#')
    .replaceAll('\\>', '>')
    .replaceAll('\\+', '+')
    .replaceAll('\\~', '~');
};

const replaceUnescapedChars = (text: string, regexes: RegExp[]): string => {
  // convert "*" to "", "_" to "", "~" to "" (all chars, which are not escaped - means with "\" in front)
  for (const regex of regexes) {
    text = text.replaceAll(regex, '');
  }
  return text;
};

const UNESCAPE_ITALIC_UNDERSCORE_IMPORT_REGEX =
  /([\_])(?<!(?:\1|\w).)(?![_*\s])(.*?[^_*\s])(?=\1)([\_])(?!\w|\3)/;
const UNESCAPE_ITALIC_UNDERSCORE_REGEX =
  /([\_])(?<!(?:\1|\w).)(?![_*\s])(.*?[^_*\s])(?=\1)([\_])(?!\w|\3)/;

export const UNESCAPE_ITALIC_UNDERSCORE: TextMatchTransformer = {
  dependencies: [],
  export: () => null,
  importRegExp: UNESCAPE_ITALIC_UNDERSCORE_IMPORT_REGEX,
  regExp: UNESCAPE_ITALIC_UNDERSCORE_REGEX,
  replace: (textNode, _) => {
    const notEscapedUnderscoreRegex = /(?<![\\]{1})[\_]{1}/g;
    const textContent = replaceUnescapedChars(textNode.getTextContent(), [
      notEscapedUnderscoreRegex,
    ]);
    textNode.setTextContent(replaceEscapedChars(textContent));
    textNode.setFormat('italic');
  },
  trigger: '_',
  type: 'text-match',
};

const UNESCAPE_ITALIC_STAR_IMPORT_REGEX =
  /([\*])(?<!(?:\1|\w).)(?![_*\s])(.*?[^_*\s])(?=\1)([\*])(?!\w|\3)/;
const UNESCAPE_ITALIC_STAR_REGEX =
  /([\*])(?<!(?:\1|\w).)(?![_*\s])(.*?[^_*\s])(?=\1)([\*])(?!\w|\3)/;

export const UNESCAPE_ITALIC_STAR: TextMatchTransformer = {
  dependencies: [],
  export: () => null,
  importRegExp: UNESCAPE_ITALIC_STAR_IMPORT_REGEX,
  regExp: UNESCAPE_ITALIC_STAR_REGEX,
  replace: (textNode, _) => {
    const notEscapedStarRegex = /(?<![\\]{1})[\*]{1}/g;
    const textContent = replaceUnescapedChars(textNode.getTextContent(), [
      notEscapedStarRegex,
    ]);
    textNode.setTextContent(replaceEscapedChars(textContent));
    textNode.setFormat('italic');
  },
  trigger: '*',
  type: 'text-match',
};

const UNESCAPE_BACKSLASH_IMPORT_REGEX = /(\\(?:\\\\)?).*?\1*[\~\*\_\{\}\[\]\(\)\#\+\-\.\!]/;
const UNESCAPE_BACKSLASH_REGEX = /(\\(?:\\\\)?).*?\1*[\~\*\_\{\}\[\]\(\)\#\+\-\.\!]$/;

export const UNESCAPE_BACKSLASH: TextMatchTransformer = {
  dependencies: [],
  export: () => null,
  importRegExp: UNESCAPE_BACKSLASH_IMPORT_REGEX,
  regExp: UNESCAPE_BACKSLASH_REGEX,
  replace: (textNode, _) => {
    if (textNode) {
      textNode.setTextContent(replaceEscapedChars(textNode.getTextContent()));
    }
  },
  trigger: '\\',
  type: 'text-match',
};

export const TO_WYSIWYG_TRANSFORMERS = [
  UNESCAPE_BACKSLASH,
  BOLD_ITALIC_UNDERSCORE,
  BOLD_ITALIC_STAR,
  BOLD_STAR,
  BOLD_UNDERSCORE,
  STRIKETHROUGH,
  UNESCAPE_ITALIC_UNDERSCORE,
  UNESCAPE_ITALIC_STAR,
  INLINE_CODE,
  HEADING,
  QUOTE,
  ORDERED_LIST,
  UNORDERED_LIST,
  LINK,
];