import marked from 'marked'
import { escape, unescape } from 'marked/src/helpers'
import { renderToString } from 'katex';

const latexRegex = /\$+([^\$\n]+?)\$+/g
//兼容之前的 ##标题式写法
const headingRegex = /^ *(#{1,6}) *([^\n]+?) *(?:#+ *)?(?:\n+|$)/
let toc = []
let ctx = ["<ul>"]

export function cleanToc() {
  toc = []
  ctx = ["<ul>"]
}

function buildToc(coll, k, level, ctx) {
  if (k >= coll.length || coll[k].level <= level) { return k }
  var node = coll[k]
  ctx.push("<li><a href='#" + node.anchor + "'>" + node.text + "</a>")
  k++
  var childCtx = []
  k = buildToc(coll, k, node.level, childCtx)
  if (childCtx.length > 0) {
    ctx.push("<ul>")
    childCtx.forEach(function (idm) {
      ctx.push(idm)
    });
    ctx.push("</ul>")
  }
  ctx.push("</li>")
  k = buildToc(coll, k, level, ctx)
  return k
}

export function getTocContent() {
  buildToc(toc, 0, 0, ctx)
  ctx.push("</ul>")
  return ctx.join("")
}

const tokenizer = {
  heading(src) {
    const cap = headingRegex.exec(src);
    if (cap) {
      return {
        type: 'heading',
        raw: cap[0],
        depth: cap[1].length,
        text: cap[2]
      };
    }
  },
  codespan(src) {
    const cap = this.rules.inline.code.exec(src);
    if (cap) {
      let text = cap[2].replace(/\n/g, ' ');
      const hasNonSpaceChars = /[^ ]/.test(text);
      const hasSpaceCharsOnBothEnds = text.startsWith(' ') && text.endsWith(' ');
      if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {
        text = text.substring(1, text.length - 1)
      }
      let match = text.match(latexRegex)
      if (match) {
        text = text.replace(latexRegex, (_, $1) => {
          return renderToString(unescape($1))
        })
      } else {
        text = escape(text, true);
      }
      return {
        type: 'codespan',
        raw: cap[0],
        text
      }
    }
  }
}

const renderer = {
  code(code, infostring, escaped) {
    const lang = (infostring || '').match(/\S*/)[0];
    if (!lang) {
      return '<pre class="prettyprint linenums"><code>'
        + (escaped ? code : escape(code, true))
        + '</code></pre>';
    }

    if (['latex', 'katex', 'math'].indexOf(lang) >= 0) {
      return `<p class='editormd-tex'>${renderToString(unescape(code))}</p>`
    } else {
      return `<pre class="prettyprint linenums"><code class="language-${infostring}">${escaped ? code : escape(code, true)}</code></pre>\n`
    }
  }
  , paragraph(text) {
    let match = text.match(latexRegex)
    if (match) {
      text = text.replace(latexRegex, (_, $1) => {
        return renderToString(unescape($1))
      })
    }
    return '<p>' + text + '</p>\n';
  },
  heading(text, level, raw, slugger) {
    let anchor = this.options.headerPrefix + raw.toLowerCase().replace(/[^\w\\u4e00-\\u9fa5]]+/g, '-');
    toc.push({
      anchor: anchor,
      level: level,
      text: text
    })
    return '<h' + level + ' id="' + anchor + '">' + text + '</h' + level + '>'
  }
}

marked.setOptions({
  silent: true,
  smartypants: true,
  gfm: true,
  pedantic: false
})

marked.use({ tokenizer, renderer });

export default marked