var hljs = require('highlight.js') var cheerio = require('cheerio') var markdown = require('markdown-it') var Token = require('markdown-it/lib/token') /** * `
` => `
`
 * `` => ``
 * @param  {string} str
 * @return {string}
 */
var addVuePreviewAttr = function (str) {
  return str.replace(/( vue file template
 * @param  {[type]} html [description]
 * @return {[type]}      [description]
 */
var renderVueTemplate = function (html, wrapper) {
  var $ = cheerio.load(html, {
    decodeEntities: false,
    lowerCaseAttributeNames: false,
    lowerCaseTags: false
  })

  $('style').remove()
  $('script').remove()

  let label = $('h1').text() || $('h2').text() || $('h3').text()
  let template =
    `
      <${wrapper}>
        ${$.html()}
      
    `
  return {template, label}
}

function markdownCompiler (source, opts) {
  this.cacheable && this.cacheable()
  var parser, preprocess
  var vueMarkdownOptions = this.options.__vueMarkdownOptions__
  var opts = Object.create(vueMarkdownOptions.__proto__) // inherit prototype
  var preventExtract = false

  opts = Object.assign(opts, vueMarkdownOptions) // assign attributes

  if (opts.preventExtract) {
    delete opts.preventExtract
    preventExtract = true
  }

  if (typeof opts.render === 'function') {
    parser = opts
  } else {
    opts = Object.assign(
      {
        preset: 'default',
        html: true,
        highlight: renderHighlight,
        wrapper: 'section'
      },
      opts
    )

    var plugins = opts.use
    preprocess = opts.preprocess

    delete opts.use
    delete opts.preprocess

    if (opts.before && typeof opts.before === 'function') {
      source = opts.before.call(this, source)
    }

    parser = markdown(opts.preset, opts)

    // add ruler:extract script and style tags from html token content
    !preventExtract &&
      parser.core.ruler.push('extract_script_or_style', function replace (
        state
      ) {
        let tag_reg = new RegExp('<(script|style)(?:[^<]|<)+', 'g')
        let newTokens = []
        state.tokens
          .filter(token => token.type == 'fence' && token.info == 'html')
          .forEach(token => {
            let tokens = (token.content.match(tag_reg) || []).map(content => {
              let t = new Token('html_block', '', 0)
              t.content = content
              return t
            })
            if (tokens.length > 0) {
              newTokens.push.apply(newTokens, tokens)
            }
          })
        state.tokens.push.apply(state.tokens, newTokens)
      })

    if (plugins) {
      plugins.forEach(function (plugin) {
        if (Array.isArray(plugin)) {
          parser.use.apply(parser, plugin)
        } else {
          parser.use(plugin)
        }
      })
    }
  }

  /**
   * override default parser rules by adding v-pre attribute on 'code' and 'pre' tags
   * @param {Array} rules rules to override
   */
  function overrideParserRules (rules) {
    if (parser && parser.renderer && parser.renderer.rules) {
      var parserRules = parser.renderer.rules
      rules.forEach(function (rule) {
        if (parserRules && parserRules[rule]) {
          var defaultRule = parserRules[rule]
          parserRules[rule] = function () {
            return addVuePreviewAttr(defaultRule.apply(this, arguments))
          }
        }
      })
    }
  }

  overrideParserRules(['code_inline', 'code_block', 'fence'])

  if (preprocess) {
    source = preprocess.call(this, parser, source)
  }

  var content = parser.render(source)
  var result = renderVueTemplate(content, opts.wrapper)

  if (opts.after && typeof opts.after === 'function') {
    result = opts.after.call(this, result)
  }
  if (opts.raw) {
    return result
  } else {
    return 'module.exports = ' + JSON.stringify(result)
  }
}

module.exports = function (source) {
  this.cacheable()

  this.options.__vueMarkdownOptions__ =
    this.query || this.vueMarkdown || this.options.vueMarkdown || {}

  var result = markdownCompiler.call(this, source)
  return result
}