import remarkGfm from 'remark-gfm';
import remarkParse from 'remark-parse';
import { unified } from 'unified';

const markdownParser = unified().use(remarkParse).use(remarkGfm);
const STANDALONE_BREAK_LINE = /^[\t ]*<br\s*\/?>[\t ]*$/im;

/**
 * Compares Markdown by parsed GFM structure so harmless marker formatting is
 * accepted while list, table, heading, code, and raw HTML changes are rejected.
 */
export function hasEquivalentMarkdownSemantics(
  source: string,
  normalized: string,
) {
  try {
    return semanticTree(source) === semanticTree(normalized);
  } catch {
    return false;
  }
}

/**
 * Removes blank-paragraph markers generated by the live editor without
 * changing an explicit HTML break that already exists in the source.
 */
export function normalizeLiveMarkdownUpdate(source: string, markdown: string) {
  if (STANDALONE_BREAK_LINE.test(source)) return markdown;
  return markdown
    .replace(/^[\t ]*<br\s*\/?>[\t ]*\n{2,}/gi, '')
    .replace(/\n{2,}[\t ]*<br\s*\/?>[\t ]*\n{2,}/gi, '\n\n')
    .replace(/\n{2,}[\t ]*<br\s*\/?>[\t ]*$/gi, '\n');
}

function semanticTree(markdown: string) {
  const normalizedLineEndings = markdown
    .replaceAll('\r\n', '\n')
    .replaceAll('\r', '\n');
  return JSON.stringify(
    markdownParser.parse(normalizedLineEndings),
    (key, value) => (key === 'position' ? undefined : value),
  );
}
