/**
 * Copyright © Volker Schukai and all contributing authors, {{copyRightYear}}. All rights reserved.
 * Node module: @schukai/monster
 *
 * This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3).
 * The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html
 *
 * For those who do not wish to adhere to the AGPLv3, a commercial license is available.
 * Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms.
 * For more information about purchasing a commercial license, please contact Volker Schukai.
 *
 * SPDX-License-Identifier: AGPL-3.0
 */

export { extractKeys };

/**
 * Extracts the keys from the given object and returns a map with the keys and values.
 *
 * @private
 * @param {object} obj
 * @param {string} keyPrefix
 * @param {string} keySeparator
 * @param {string} valueSeparator
 * @return {Map<any, any>}
 */
function extractKeys(
	obj,
	keyPrefix = "",
	keySeparator = "-",
	valueSeparator = ".",
) {
	const resultMap = new Map();

	function normalizeKeySegment(value) {
		return String(value).toLowerCase();
	}

	function toKebabCase(value) {
		return String(value)
			.replace(/([a-z0-9])([A-Z])/g, "$1-$2")
			.toLowerCase();
	}

	function appendKeys(compactKey, kebabKey, valuePath) {
		resultMap.set(compactKey, valuePath);
		if (kebabKey !== compactKey) {
			resultMap.set(kebabKey, valuePath);
		}
	}

	function helper(
		currentObj,
		currentCompactKeyPrefix,
		currentKebabKeyPrefix,
		currentValuePrefix,
	) {
		for (const key in currentObj) {
			const compactSegment = normalizeKeySegment(key);
			const kebabSegment = toKebabCase(key);

			if (
				currentObj[key] !== null &&
				typeof currentObj[key] === "object" &&
				!Array.isArray(currentObj[key])
			) {
				const newCompactKeyPrefix = currentCompactKeyPrefix
					? currentCompactKeyPrefix + keySeparator + compactSegment
					: compactSegment;
				const newKebabKeyPrefix = currentKebabKeyPrefix
					? currentKebabKeyPrefix + keySeparator + kebabSegment
					: kebabSegment;
				const newValuePrefix = currentValuePrefix
					? currentValuePrefix + valueSeparator + key
					: key;
				helper(
					currentObj[key],
					newCompactKeyPrefix,
					newKebabKeyPrefix,
					newValuePrefix,
				);
			} else {
				const finalCompactKey = currentCompactKeyPrefix
					? currentCompactKeyPrefix + keySeparator + compactSegment
					: compactSegment;
				const finalKebabKey = currentKebabKeyPrefix
					? currentKebabKeyPrefix + keySeparator + kebabSegment
					: kebabSegment;
				const finalValue = currentValuePrefix
					? currentValuePrefix + valueSeparator + key
					: key;
				appendKeys(finalCompactKey, finalKebabKey, finalValue);
			}
		}
	}

	helper(obj, keyPrefix, keyPrefix, keyPrefix);
	return resultMap;
}
