const { createSlug } = require('./strings.cjs')

/**
 * Turns headings into clickable, deep linkable anchors. The provided doc should be a document object provided by JSDOM.
 * The same document will be returned with the appropriate DOM manipulations.
 */
module.exports = function (doc, options) {
    options = {
        levels: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'], // the headings to convert
        className: 'anchor-heading', // the class name to add
        within: 'body', // the element containing the target headings
        ...options,
    }

    const within = doc.querySelector(options.within)

    if (!within) {
        return doc
    }

    within.querySelectorAll('h1, h2, h3, h4, h5, h6').forEach(heading => {
        const hasAnchor = heading.querySelector('a')
        const anchor = doc.createElement('a')
        let id = heading.textContent ?? ''
        let suffix = 0

        // Skip heading levels we don't care about
        if (!options.levels?.includes(heading.tagName.toLowerCase())) {
            return
        }

        // Convert dots to underscores
        id = id.replace(/\./g, '_')

        // Turn it into a slug
        id = createSlug(id)

        // Make sure it starts with a letter
        if (!/^[a-z]/i.test(id)) {
            id = `id_${id}`
        }

        // Make sure the id is unique
        const originalId = id
        while (doc.getElementById(id) !== null) {
            id = `${originalId}-${++suffix}`
        }

        if (hasAnchor || !id) return

        heading.setAttribute('id', id)
        anchor.setAttribute('href', `#${encodeURIComponent(id)}`)
        anchor.setAttribute('aria-label', `Direct link to "${heading.textContent}"`)

        if (options.className) {
            heading.classList.add(options.className)
        }

        // Append the anchor
        heading.append(anchor)
    })

    return doc
}
