import katex from 'katex';

const DELIMITER_LIST = [
    { left: '$$', right: '$$', display: false },
    { left: '$', right: '$', display: false },
    { left: '\\pu{', right: '}', display: false },
    { left: '\\ce{', right: '}', display: false },
    { left: '\\(', right: '\\)', display: false },
    { left: '( ', right: ' )', display: false },
    { left: '\\[', right: '\\]', display: true },
    { left: '[', right: ']', display: true }
]

// const DELIMITER_LIST = [
//     { left: '$$', right: '$$', display: false },
//     { left: '$', right: '$', display: false },
// ];

// const inlineRule = /^(\${1,2})(?!\$)((?:\\.|[^\\\n])*?(?:\\.|[^\\\n\$]))\1(?=[\s?!\.,:？！。，：]|$)/;
// const blockRule = /^(\${1,2})\n((?:\\[^]|[^\\])+?)\n\1(?:\n|$)/;

let inlinePatterns = [];
let blockPatterns = [];

function escapeRegex(string) {
    return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}

function generateRegexRules(delimiters) {
    delimiters.forEach(delimiter => {
        const { left, right } = delimiter;
        // Ensure regex-safe delimiters
        const escapedLeft = escapeRegex(left);
        const escapedRight = escapeRegex(right);

        // Inline pattern - Capture group $1, token content, followed by end delimiter and normal punctuation marks.
        // Example: $text$
        inlinePatterns.push(`${escapedLeft}((?:\\\\.|[^\\\\\\n])*?(?:\\\\.|[^\\\\\\n${escapedRight}]))${escapedRight}`);

        // Block pattern - Starts and ends with the delimiter on new lines. Example:
        // $$\ncontent here\n$$
        blockPatterns.push(`${escapedLeft}\n((?:\\\\[^]|[^\\\\])+?)\n${escapedRight}`);
    });

    const inlineRule = new RegExp(`^(${inlinePatterns.join('|')})(?=[\\s?!.,:？！。，：]|$)`, 'u');
    const blockRule = new RegExp(`^(${blockPatterns.join('|')})(?:\n|$)`, 'u');

    return { inlineRule, blockRule };
}

const { inlineRule, blockRule } = generateRegexRules(DELIMITER_LIST);



export default function(options = {}) {
  return {
    extensions: [
      inlineKatex(options, createRenderer(options, false)),
      blockKatex(options, createRenderer(options, true)),
    ],
  };
}

function createRenderer(options, newlineAfter) {
  return (token) => katex.renderToString(token.text, { ...options, displayMode: token.displayMode }) + (newlineAfter ? '\n' : '');
}

function inlineKatex(options, renderer) {
  const ruleReg =  inlineRule;
  return {
    name: 'inlineKatex',
    level: 'inline',
    start(src) {
      let index;
      let indexSrc = src;

      while (indexSrc) {
        index = indexSrc.indexOf('$');
        if (index === -1) {
          return;
        }
        const f = index === 0 || indexSrc.charAt(index - 1) === ' ';
        if (f) {
          const possibleKatex = indexSrc.substring(index);

          if (possibleKatex.match(ruleReg)) {
            return index;
          }
        }

        indexSrc = indexSrc.substring(index + 1).replace(/^\$+/, '');
      }
    },
    tokenizer(src, tokens) {
      const match = src.match(ruleReg);

      if (match) {
        const text = match.slice(2).filter((item) => item).find((item) => item.trim());

        return {
          type: 'inlineKatex',
          raw: match[0],
          text: text,
        };
      }
    },
    renderer,
  };
}

function blockKatex(options, renderer) {
  return {
    name: 'blockKatex',
    level: 'block',
    tokenizer(src, tokens) {
      const match = src.match(blockRule);

      if (match) {
        const text = match.slice(2).filter((item) => item).find((item) => item.trim());

        return {
          type: 'blockKatex',
          raw: match[0],
          text: text,
        };
      }
    },
    renderer,
  };
}

