import truncate from 'lodash/truncate';

import { parseLinksFromText } from './parseLinks';

import { escapeRegExp } from '../../../../utils/utils';

export const generateMarkdownText = (text?: string) => {
  if (!text) {
    return null;
  }

  const normalizedText = text.replace(/\uFFFC/g, ' ');

  // Trim the extra spaces from the text.
  let resultText = normalizedText.trim();

  // List of all the links present in the text.
  const linkInfos = parseLinksFromText(resultText);

  for (const linkInfo of linkInfos) {
    const displayLink = truncate(linkInfo.raw, {
      length: 200,
      omission: '...',
    });
    // Convert raw links/emails in the text to respective markdown syntax.
    // Eg: Hi @getstream.io -> Hi @[getstream.io](getstream.io).
    const normalRegEx = new RegExp(escapeRegExp(linkInfo.raw), 'g');
    const markdown = `[${displayLink}](${linkInfo.url})`;
    resultText = normalizedText.replace(normalRegEx, markdown);

    // After previous step, in some cases, the mentioned user after `@` might have a link/email so we convert it back to normal raw text.
    // Eg: Hi, @[test.user@gmail.com](mailto:test.user@gmail.com) to @test.user@gmail.com.
    const mentionsRegex = new RegExp(
      `@\\[${escapeRegExp(displayLink)}\\]\\(${escapeRegExp(linkInfo.url)}\\)`,
      'g',
    );
    resultText = resultText.replace(mentionsRegex, `@${displayLink}`);
  }

  // Escape the " and ' characters, except in code blocks where we deem this allowed.
  resultText = resultText.replace(/(```[\s\S]*?```|`.*?`)|[<"']/g, (match, code) => {
    if (code) {
      return code;
    }
    return `\\${match}`;
  });

  // Remove whitespaces that come directly after newlines except in code blocks where we deem this allowed.
  resultText = resultText.replace(/(```[\s\S]*?```|`.*?`)|\n[ ]{2,}/g, (_, code) => {
    if (code) {
      return code;
    }
    return '\n';
  });

  // Always replace \n``` with \n\n``` to force the markdown state machine to treat it as a separate block. Otherwise, code blocks inside of list
  // items for example were broken. We clean up the code block closing state within the rendering itself.
  resultText = resultText.replace(/\n```/g, '\n\n```');

  return resultText;
};
