const accentMap = {
	à: 'a',
	á: 'a',
	ä: 'a',
	å: 'a',
	ã: 'a',
	â: 'a',
	æ: 'ae',
	ç: 'c',
	è: 'e',
	é: 'e',
	ë: 'e',
	ẽ: 'e',
	ê: 'e',
	ì: 'i',
	í: 'i',
	ï: 'i',
	ĩ: 'i',
	î: 'i',
	ǹ: 'n',
	ń: 'n',
	ñ: 'n',
	ò: 'o',
	ó: 'o',
	ö: 'o',
	õ: 'o',
	ô: 'o',
	ø: 'o',
	œ: 'oe',
	ß: 'ss',
	ù: 'u',
	ú: 'u',
	ü: 'u',
	ũ: 'u',
	û: 'u',
	ỳ: 'y',
	ý: 'y',
	ÿ: 'y',
	ỹ: 'y',
};

const plainCharRegex = /[a-z0-9]/i;
const defaultPunctuationRegex = /[.,?!:;&'‘’"“”…()[\]{}<>/*—]/;
const defaultSymbolRegex = /[@$€£#%^+=\\~]/;

export default function slugify(strings, delimiter = '-', {
	limit = 1000,
	lower = true,
	encode = false,
	accents: keepAccents = false,
	punctuation: keepPunctuation = 'split',
	punctuationRegex = defaultPunctuationRegex,
	symbols: keepSymbols = false,
	symbolRegex = defaultSymbolRegex,
} = {}) {
	if (!strings || (typeof strings !== 'string' && !Array.isArray(strings))) {
		return strings;
	}

	const string = [].concat(strings).join(' ');

	const casedString = lower
		? string.toLowerCase()
		: string;

	const normalized = casedString
		.replace(/[_-]+/g, ' ')
		.split('')
		.map((char) => {
			if (char === ' ') {
				return char;
			}

			const lowChar = char.toLowerCase();

			if (accentMap[lowChar]) {
				if (keepAccents) {
					return char;
				}

				// match original case after mapping
				if (char === lowChar) {
					return accentMap[lowChar];
				}

				return accentMap[lowChar].toUpperCase();
			}

			if (plainCharRegex.test(char)) {
				return char;
			}

			if (punctuationRegex.test(char)) {
				if (keepPunctuation === 'split') {
					return ' ';
				}

				if (keepPunctuation) {
					return char;
				}
			}

			if (symbolRegex.test(char)) {
				if (keepSymbols === 'split') {
					return ' ';
				}

				if (keepSymbols) {
					return char;
				}
			}

			return '';
		})
		.join('');

	const components = normalized.trim().split(/\s+/).filter(Boolean);

	if (components.length === 0) {
		return '';
	}

	const slug = components.reduce((acc, component, index) => {
		const accSlug = `${acc}${index > 0 ? delimiter : ''}${component}`;

		if (accSlug.length < limit) {
			return accSlug;
		}

		return acc;
	}).slice(0, limit); // in case first word exceeds limit

	if (encode) {
		return encodeURI(slug);
	}

	return slug;
}
