/**
 * Support titles, line highlights and more for code blocks
 */
import { Parser } from 'acorn'
import { visit } from 'unist-util-visit'
import parseAttr from 'md-attr-parser'

import getProps from './getProps.mjs'

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 = node.value
                }

                const data = node.data || (node.data = {})
                const hProps = data.hProperties || (data.hProperties = {})

                const meta = getProps(Parser.parse(node.meta, { ecmaVersion: 'latest' }))

                node.data.hProperties = Object.assign({}, hProps, attrs, meta)
            }
        })

        visit(tree, 'inlineCode', (node) => {
            node.type = 'mdxJsxTextElement'
            node.name = 'InlineCode'
            node.children = [
                {
                    type: 'text',
                    value: node.value,
                },
            ]
            node.data = { _mdxExplicitJsx: true }
        })

        return tree
    }
    return transformer
}

export default remarkCodeBlocks