/**
 * Support titles, line highlights and more for code blocks
 */

const visit = require('unist-util-visit')
const parseAttr = require('md-attr-parser')

const defaultOptions = {
    defaultPrefix: '###',
    prefixMap: {
        javascript: '///',
        jsx: '///',
    },
    languageAliases: {},
    githubRegex: /^https:\/\/(github|raw.githubusercontent).com/,
    prompts: ['$'],
}

module.exports = ({ markdownAST }, userOptions = {}) => {
    const options = Object.assign({}, defaultOptions, userOptions)
    visit(markdownAST, 'code', node => {
        if (node.value) {
            const langName = node.lang || 'none'
            const lang = options.languageAliases[langName] || langName
            const prefix = options.prefixMap[lang] || options.defaultPrefix
            const lines = node.value.split('\n')
            let attrs = { lang }
            const firstLine = lines[0].trim()
            if (firstLine && firstLine.startsWith(prefix)) {
                const title = firstLine.slice(prefix.length).trim()
                attrs.title = title
                // Check for attributes in title, e.g. {executable="true"}
                const parsed = title.split(/\{(.*?)\}/)
                if (parsed.length >= 2 && parsed[1]) {
                    const { prop } = parseAttr(parsed[1])
                    attrs = { ...attrs, ...prop, title: parsed[0].trim(), lang }
                }
                // Overwrite the code text with the rest of the lines
                node.value = lines.slice(1).join('\n')
            } else if (firstLine && options.githubRegex.test(firstLine)) {
                // GitHub URL
                attrs.github = 'true'
            }
            // If it's a bash code block and single line, check for prompts
            if (lang === 'bash') {
                const [trueFirstLine, ...trueLines] = node.value.split('\n')
                for (let prompt of options.prompts) {
                    if (trueFirstLine.startsWith(prompt)) {
                        const content = [trueFirstLine.slice(prompt.length).trim(), ...trueLines]
                        attrs.prompt = prompt
                        node.value = content.join('\n')
                        break
                    }
                }
            }
            const data = node.data || (node.data = {})
            const hProps = data.hProperties || (data.hProperties = {})
            node.data.hProperties = Object.assign({}, hProps, attrs)
        }
    })
    return markdownAST
}
