//
// Helper Functions
//

function lookupVariable(context, variableName) {
	const { frames, importantScope } = context

	return tree.Variable.prototype.find(frames, frame => {
		const { value, important } = frame.variable(variableName) || {}

		if (value === undefined)
			return

		if (important && importantScope[importantScope.length - 1])
			importantScope[importantScope.length - 1].important = important

		return value.eval(context)
	})
}

// @TODO: [@calvinjuarez] unify this function between files, maybe even canonize it as a
// `Ruleset`/`DetachedRuleset` method at some point.
function rulesetToMap(context, { ruleset: { rules } } = { ruleset: { rules: [] } }) {
	const map = {}

	rules.forEach(rule => {
		// Not exactly sure how to handle other types (or if they should be handled at all).
		if (! (rule instanceof tree.Declaration))
			return

		const { name: key, value } = rule.eval(context)

		map[key] = value
	})

	return map
}

//
// Less Functions
//

// Requires the use of quotes around data URIs.
functions.add('escape-svg', function (value = {}) {
	let escapedStr = value.toCSS ? value.toCSS() : ''

	if (! escapedStr.includes('data:image/svg+xml'))
		return value

	const escapeCharsVar = lookupVariable(this.context, '@escaped-characters')
	let escapeCharsMap = {}

	// Currently Less treats the `@escaped-characters` variable as a string instead of a ruleset, due
	// to its unconventional use of special characters like `<` as property names. In case this is
	// fixed in the future, we’ll handle both possible values here (string and ruleset).
	if (escapeCharsVar instanceof tree.Quoted) {
		// Remove leading `{` and trailing `}` as well as the last instance of a `;`, then split by
		// `;`.
		const escapeCharsKeyValueArr = escapeCharsVar.value.replace(/[{}\s]+|;(?=\n})/g, '').split(';')

		escapeCharsKeyValueArr.forEach(escapeCharKeyValueStr => {
			const [key, value] = escapeCharKeyValueStr.split(':')

			escapeCharsMap[key] = value
		})
	} else
		escapeCharsMap = rulesetToMap(this.context, lookupVariable(this.context, '@escaped-characters'))

	let escapeCharsMapKeys = []

	try {
		escapeCharsMapKeys = Object.keys(escapeCharsMap)
	} catch (err) {
		// Do nothing.
	}

	let shouldAddURLWrapper = false

	// Strip the `url()` wrapping the string, if present (to prevent it from being escaped).
	if (escapedStr.startsWith('url(')) {
		escapedStr = escapedStr.replace(/^url\(|\)$/g, '')
		shouldAddURLWrapper = true
	}

	escapeCharsMapKeys.forEach(key => {
		const value = escapeCharsMap[key]

		if (key === ')' || key === '(')
			key = `\\${key}`

		escapedStr = escapedStr.replace(new RegExp(key, 'g'), value)
	})

	// Re-add the `url()` wrapper if necessary.
	if (shouldAddURLWrapper)
		escapedStr = `url(${escapedStr})`

	return new tree.Quoted('', escapedStr)
})
