import { regEx } from "../../../util/regex.js";
//#region lib/modules/versioning/maven/compare.ts
const PREFIX_DOT = "PREFIX_DOT";
const PREFIX_HYPHEN = "PREFIX_HYPHEN";
const ALPHA_SUFFIX = "-alpha";
const TYPE_NUMBER = "TYPE_NUMBER";
const TYPE_QUALIFIER = "TYPE_QUALIFIER";
function iterateChars(str, cb) {
	let prev = null;
	let next = null;
	for (let i = 0; i < str.length; i += 1) {
		next = str.charAt(i);
		cb(prev, next);
		prev = next;
	}
	cb(prev, null);
}
function isDigit(char) {
	return regEx(/^\d$/).test(char);
}
function isLetter(char) {
	return regEx(/^[a-z_+]$/i).test(char);
}
function isTransition(prevChar, nextChar) {
	return isDigit(prevChar) && isLetter(nextChar) || isLetter(prevChar) && isDigit(nextChar);
}
function iterateTokens(versionStr, cb) {
	let currentPrefix = "";
	let currentVal = "";
	function yieldToken(transition = false) {
		const val = currentVal || "0";
		if (regEx(/^\d+$/).test(val)) cb({
			prefix: currentPrefix,
			type: TYPE_NUMBER,
			val: parseInt(val, 10),
			isTransition: transition
		});
		else cb({
			prefix: currentPrefix,
			type: TYPE_QUALIFIER,
			val,
			isTransition: transition
		});
	}
	iterateChars(versionStr, (prevChar, nextChar) => {
		if (nextChar === null) yieldToken();
		else if (nextChar === "-") {
			yieldToken();
			currentPrefix = PREFIX_HYPHEN;
			currentVal = "";
		} else if (nextChar === ".") {
			yieldToken();
			currentPrefix = PREFIX_DOT;
			currentVal = "";
		} else if (prevChar === null && (nextChar === "v" || nextChar === "V")) currentPrefix = nextChar;
		else if (currentVal !== "" && isTransition(prevChar, nextChar)) {
			yieldToken(true);
			currentPrefix = PREFIX_HYPHEN;
			currentVal = nextChar;
		} else if (currentVal === "" && (currentPrefix === "v" || currentPrefix === "V") && !isDigit(nextChar)) {
			currentVal = currentVal.concat(currentPrefix, nextChar);
			currentPrefix = "";
		} else currentVal = currentVal.concat(nextChar);
	});
}
function isNull(token) {
	const val = token.val;
	return val === 0 || val === "" || val === "final" || val === "ga" || val === "release" || val === "latest" || val === "sr";
}
function tokenize(versionStr, preserveMinorZeroes = false) {
	let buf = [];
	let result = [];
	let leadingZero = true;
	iterateTokens(versionStr.toLowerCase(), (token) => {
		if (token.prefix === "PREFIX_HYPHEN" || token.type === "TYPE_QUALIFIER") buf = [];
		buf.push(token);
		if (!isNull(token)) {
			leadingZero = false;
			result = result.concat(buf);
			buf = [];
		} else if (leadingZero || preserveMinorZeroes) {
			result = result.concat(buf);
			buf = [];
		}
	});
	return result;
}
function nullFor(token) {
	return token.type === "TYPE_NUMBER" ? {
		prefix: token.prefix,
		type: TYPE_NUMBER,
		val: 0
	} : {
		prefix: token.prefix,
		type: TYPE_QUALIFIER,
		val: ""
	};
}
function commonOrder(token) {
	if (token.type === "TYPE_QUALIFIER") return 1;
	if (token.prefix === "PREFIX_HYPHEN" && token.type === "TYPE_NUMBER") return 2;
	return 3;
}
const QualifierTypes = {
	Alpha: 1,
	Beta: 2,
	Milestone: 3,
	RC: 4,
	Snapshot: 5,
	Release: 6,
	SP: 7
};
function qualifierType(token) {
	const val = token.val;
	if (val === "alpha" || token.isTransition && val === "a") return QualifierTypes.Alpha;
	if (val === "beta" || token.isTransition && val === "b") return QualifierTypes.Beta;
	if (val === "milestone" || token.isTransition && val === "m") return QualifierTypes.Milestone;
	if (val === "rc" || val === "cr" || val === "preview") return QualifierTypes.RC;
	if (val === "snapshot" || val === "snap") return QualifierTypes.Snapshot;
	if (val === "" || val === "final" || val === "ga" || val === "release" || val === "latest" || val === "sr") return QualifierTypes.Release;
	if (val === "sp") return QualifierTypes.SP;
	return null;
}
function qualifierCmp(left, right) {
	const leftOrder = qualifierType(left);
	const rightOrder = qualifierType(right);
	if (leftOrder && rightOrder) {
		if (leftOrder < rightOrder) return -1;
		if (leftOrder > rightOrder) return 1;
		return 0;
	}
	if (leftOrder && leftOrder < QualifierTypes.Release) return -1;
	if (rightOrder && rightOrder < QualifierTypes.Release) return 1;
	if (left.val < right.val) return -1;
	if (left.val > right.val) return 1;
	return 0;
}
function tokenCmp(left, right) {
	const leftOrder = commonOrder(left);
	const rightOrder = commonOrder(right);
	if (leftOrder < rightOrder) return -1;
	if (leftOrder > rightOrder) return 1;
	if (left.type === "TYPE_NUMBER" && right.type === "TYPE_NUMBER") {
		if (left.val < right.val) return -1;
		if (left.val > right.val) return 1;
		return 0;
	}
	return qualifierCmp(left, right);
}
function compare(left, right) {
	const leftTokens = tokenize(left);
	const rightTokens = tokenize(right);
	const length = Math.max(leftTokens.length, rightTokens.length);
	for (let idx = 0; idx < length; idx += 1) {
		const cmpResult = tokenCmp(leftTokens[idx] || nullFor(rightTokens[idx]), rightTokens[idx] || nullFor(leftTokens[idx]));
		if (cmpResult !== 0) return cmpResult;
	}
	return 0;
}
function isVersion(version) {
	if (!version || typeof version !== "string") return false;
	if (!regEx(/^[-.a-z_+0-9]+$/i).test(version)) return false;
	if (regEx(/^[.-]/).test(version)) return false;
	if (regEx(/[.-]$/).test(version)) return false;
	if (["latest", "release"].includes(version.toLowerCase())) return false;
	return !!tokenize(version).length;
}
const INCLUDING_POINT = "INCLUDING_POINT";
const EXCLUDING_POINT = "EXCLUDING_POINT";
function parseRange(rangeStr) {
	function emptyInterval() {
		return {
			leftType: null,
			leftValue: null,
			leftBracket: null,
			rightType: null,
			rightValue: null,
			rightBracket: null
		};
	}
	const commaSplit = rangeStr.split(regEx(/\s*,\s*/));
	let ranges = [];
	let interval = emptyInterval();
	commaSplit.forEach((subStr) => {
		if (!ranges) return;
		if (interval.leftType === null) if (regEx(/^\[.*]$/).test(subStr)) {
			const ver = subStr.slice(1, -1);
			ranges.push({
				leftType: INCLUDING_POINT,
				leftValue: ver,
				leftBracket: "[",
				rightType: INCLUDING_POINT,
				rightValue: ver,
				rightBracket: "]"
			});
			interval = emptyInterval();
		} else if (subStr.startsWith("[")) {
			const ver = subStr.slice(1);
			interval.leftType = INCLUDING_POINT;
			interval.leftValue = ver;
			interval.leftBracket = "[";
		} else if (subStr.startsWith("(") || subStr.startsWith("]")) {
			const ver = subStr.slice(1);
			interval.leftType = EXCLUDING_POINT;
			interval.leftValue = ver;
			interval.leftBracket = subStr[0];
		} else ranges = null;
		else if (subStr.endsWith("]")) {
			const ver = subStr.slice(0, -1);
			interval.rightType = INCLUDING_POINT;
			interval.rightValue = ver;
			interval.rightBracket = "]";
			ranges.push(interval);
			interval = emptyInterval();
		} else if (subStr.endsWith(")") || subStr.endsWith("[")) {
			const ver = subStr.slice(0, -1);
			interval.rightType = EXCLUDING_POINT;
			interval.rightValue = ver;
			interval.rightBracket = subStr.endsWith(")") ? ")" : "[";
			ranges.push(interval);
			interval = emptyInterval();
		} else ranges = null;
	});
	if (interval.leftType) return null;
	if (!ranges?.length) return null;
	const lastIdx = ranges.length - 1;
	let prevValue = null;
	const result = [];
	for (let idx = 0; idx < ranges.length; idx += 1) {
		const range = ranges[idx];
		const { leftType, leftValue, rightType, rightValue } = range;
		if (idx === 0 && leftValue === "") {
			if (leftType === "EXCLUDING_POINT" && isVersion(rightValue)) {
				prevValue = rightValue;
				result.push({
					...range,
					leftValue: null
				});
				continue;
			}
			return null;
		}
		if (idx === lastIdx && rightValue === "") {
			if (rightType === "EXCLUDING_POINT" && isVersion(leftValue)) {
				if (prevValue && compare(prevValue, leftValue) === 1) return null;
				result.push({
					...range,
					rightValue: null
				});
				continue;
			}
			return null;
		}
		if (isVersion(leftValue) && isVersion(rightValue)) {
			if (compare(leftValue, rightValue) === 1) return null;
			if (prevValue && compare(prevValue, leftValue) === 1) return null;
			prevValue = rightValue;
			result.push(range);
			continue;
		}
		return null;
	}
	return result;
}
function isValid(str) {
	if (!str) return false;
	return isVersion(str) || !!parseRange(str);
}
function rangeToStr(fullRange) {
	if (fullRange === null) return null;
	function valToStr(val) {
		return val ?? "";
	}
	if (fullRange.length === 1) {
		const { leftBracket, rightBracket, leftValue, rightValue } = fullRange[0];
		if (leftValue === rightValue && leftBracket === "[" && rightBracket === "]") return `[${valToStr(leftValue)}]`;
	}
	return fullRange.map((val) => [
		val.leftBracket,
		valToStr(val.leftValue),
		",",
		valToStr(val.rightValue),
		val.rightBracket
	].join("")).join(",");
}
function tokensToStr(tokens) {
	let isTransition = false;
	return tokens.reduce((result, token) => {
		let prefix;
		if (token.prefix === "PREFIX_DOT") prefix = ".";
		else if (token.prefix === "PREFIX_HYPHEN") prefix = isTransition === true ? "" : "-";
		else prefix = token.prefix;
		isTransition = token.isTransition;
		return `${result}${prefix}${token.val}`;
	}, "");
}
function coerceRangeValue(prev, next) {
	const prevTokens = tokenize(prev, true);
	const nextTokens = tokenize(next, true);
	const resultTokens = nextTokens.slice(0, prevTokens.length);
	const align = Math.max(0, prevTokens.length - nextTokens.length);
	if (align > 0) resultTokens.push(...prevTokens.slice(prevTokens.length - align));
	return tokensToStr(resultTokens);
}
function incrementRangeValue(value) {
	const tokens = tokenize(value);
	const lastToken = tokens.at(-1);
	if (typeof lastToken.val === "number") {
		lastToken.val += 1;
		return coerceRangeValue(value, tokensToStr(tokens));
	}
	return value;
}
function autoExtendMavenRange(currentRepresentation, newValue) {
	const range = parseRange(currentRepresentation);
	if (!range) return currentRepresentation;
	function isPoint(vals) {
		if (vals.length !== 1) return false;
		const { leftType, leftValue, rightType, rightValue } = vals[0];
		return leftType === "INCLUDING_POINT" && leftType === rightType && leftValue === rightValue;
	}
	if (isPoint(range)) return `[${newValue}]`;
	const interval = [...range].reverse().find((elem) => {
		const { rightType, rightValue } = elem;
		return rightValue === null || rightType === "INCLUDING_POINT" && compare(rightValue, newValue) === -1 || rightType === "EXCLUDING_POINT" && compare(rightValue, newValue) !== 1;
	});
	if (!interval) return currentRepresentation;
	const { leftValue, rightValue } = interval;
	if (leftValue !== null && rightValue !== null && incrementRangeValue(leftValue) === rightValue) {
		if (compare(newValue, leftValue) !== -1) {
			interval.leftValue = coerceRangeValue(leftValue, newValue);
			interval.rightValue = incrementRangeValue(interval.leftValue);
		}
	} else if (leftValue !== null && rightValue !== null && incrementRangeValue(leftValue) + ALPHA_SUFFIX === rightValue) {
		interval.leftValue = coerceRangeValue(leftValue, newValue);
		interval.rightValue = incrementRangeValue(interval.leftValue) + ALPHA_SUFFIX;
	} else if (rightValue !== null) if (interval.rightType === "INCLUDING_POINT") if (typeof tokenize(rightValue).at(-1).val === "number") interval.rightValue = coerceRangeValue(rightValue, newValue);
	else interval.rightValue = newValue;
	else interval.rightValue = incrementRangeValue(coerceRangeValue(rightValue, newValue));
	else if (leftValue !== null) interval.leftValue = coerceRangeValue(leftValue, newValue);
	return rangeToStr(range);
}
function isSubversion(majorVersion, minorVersion) {
	const majorTokens = tokenize(majorVersion);
	const minorTokens = tokenize(minorVersion);
	let result = true;
	const len = majorTokens.length;
	for (let idx = 0; idx < len; idx += 1) {
		const major = majorTokens[idx];
		if (tokenCmp(major, minorTokens[idx] || nullFor(majorTokens[idx])) !== 0) {
			result = false;
			break;
		}
	}
	return result;
}
//#endregion
export { EXCLUDING_POINT, INCLUDING_POINT, PREFIX_DOT, PREFIX_HYPHEN, QualifierTypes, TYPE_NUMBER, TYPE_QUALIFIER, autoExtendMavenRange, compare, isVersion as isSingleVersion, isVersion, isSubversion, isValid, parseRange, qualifierType, rangeToStr, tokenize };

//# sourceMappingURL=compare.js.map