import { A_START_CHAR, B_START_CHAR, C_START_CHAR, A_CHARS, B_CHARS, C_CHARS } from './constants';

// Match Set functions
const matchSetALength = (string) => string.match(new RegExp(`^${A_CHARS}*`))[0].length;
const matchSetBLength = (string) => string.match(new RegExp(`^${B_CHARS}*`))[0].length;
const matchSetC = (string) => string.match(new RegExp(`^${C_CHARS}*`))[0];

// CODE128A or CODE128B
function autoSelectFromAB(string, isA){
	const ranges = isA ? A_CHARS : B_CHARS;
	const untilC = string.match(new RegExp(`^(${ranges}+?)(([0-9]{2}){2,})([^0-9]|$)`));

	if (untilC) {
		return (
			untilC[1] +
			String.fromCharCode(204) +
			autoSelectFromC(string.substring(untilC[1].length))
		);
	}

	const chars = string.match(new RegExp(`^${ranges}+`))[0];

	if (chars.length === string.length) {
		return string;
	}

	return (
		chars +
		String.fromCharCode(isA ? 205 : 206) +
		autoSelectFromAB(string.substring(chars.length), !isA)
	);
}

// CODE128C
function autoSelectFromC(string) {
	const cMatch = matchSetC(string);
	const length = cMatch.length;

	if (length === string.length) {
		return string;
	}

	string = string.substring(length);

	// Select A/B depending on the longest match
	const isA = matchSetALength(string) >= matchSetBLength(string);
	return cMatch + String.fromCharCode(isA ? 206 : 205) + autoSelectFromAB(string, isA);
}

// Detect Code Set (A, B or C) and format the string
export default (string) => {
	let newString;
	const cLength = matchSetC(string).length;

	// Select 128C if the string start with enough digits
	if (cLength >= 2) {
		newString = C_START_CHAR + autoSelectFromC(string);
	} else {
		// Select A/B depending on the longest match
		const isA = matchSetALength(string) > matchSetBLength(string);
		newString = (isA ? A_START_CHAR : B_START_CHAR) + autoSelectFromAB(string, isA);
	}

	return newString.replace(
		/[\xCD\xCE]([^])[\xCD\xCE]/, // Any sequence between 205 and 206 characters
		(match, char) => String.fromCharCode(203) + char
	);
};
