/**
 * 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: {},
    prompts: ['$'],
}

function remarkCodeBlocks(userOptions = {}) {
    const options = Object.assign({}, defaultOptions, userOptions)

    function transformer(tree) {
        visit(tree, '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 && /^https:\/\/github.com/.test(firstLine)) ||
                    firstLine.startsWith('%%GITHUB_')
                ) {
                    // 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 tree
    }
    return transformer
}

module.exports = remarkCodeBlocks