export const CalcolaCodiceFiscale = ({
	cognome,
	nome,
	dataNascita,
	sesso,
	catasto,
}: {
	cognome: string;
	nome: string;
	dataNascita: Date;
	sesso: "M" | "F";
	catasto: string;
}) => {
	const data = new Date(dataNascita);

	const cf15 = `${calcoloCognome(cognome)}${calcoloNome(nome)}${data.getFullYear().toString().slice(-2)}${getMonthLetterCF(data.getMonth())}${getDayCF(data.getDate(), sesso)}${catasto}`;
	const cf = `${cf15}${genCarattereControllo(cf15)}`;
	const omocodie = genOmocodie(cf);
	return {
		cf,
		omocodie,
	};
};

function calcoloCognome(cognome: string): string {
	const consonanti = cognome
		.toUpperCase()
		.replace(/[^BCDFGHJKLMNPQRSTVWXYZ]/g, "");
	const vocali = cognome.toUpperCase().replace(/[^AEIOU]/g, "");

	if (consonanti.length >= 3) {
		return consonanti.substring(0, 3);
	}
	return `${consonanti + vocali}XXX`.substring(0, 3);
}

function calcoloNome(nome: string): string {
	const consonanti = nome
		.toUpperCase()
		.replace(/[^BCDFGHJKLMNPQRSTVWXYZ]/g, "");
	const vocali = nome.toUpperCase().replace(/[^AEIOU]/g, "");

	if (consonanti.length >= 4) {
		const c0 = consonanti[0];
		const c2 = consonanti[2];
		const c3 = consonanti[3];
		if (!c0 || !c2 || !c3) {
			throw new Error("Invalid name for CF generation");
		}
		// (4 o più consonanti): 1ª, 3ª e 4ª consonante
		return c0 + c2 + c3;
	}
	// (meno di 4 consonanti): prime consonanti + eventuali vocali
	const res = `${consonanti + vocali}XXX`.substring(0, 3);
	return res;
}
const lettere_mesi = "ABCDEHLMPRST";
const getMonthLetterCF = (month: number) => {
	return lettere_mesi[month];
};

const getDayCF = (day: number, sesso: string) => {
	if (sesso === "M") {
		return day.toString().padStart(2, "0");
	}
	return (day + 40).toString().padStart(2, "0");
};

const set1 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

const set2 = "ABCDEFGHIJABCDEFGHIJKLMNOPQRSTUVWXYZ";

const setpari = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

const setdisp = "BAKPLCQDREVOSFTGUHMINJWZYX";

const setcontrollo = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

const genCarattereControllo = (str: string) => {
	let s = 0;

	for (let i = 1; i <= 13; i += 2)
		s += setpari.indexOf(set2.charAt(set1.indexOf(str.charAt(i))));

	for (let i = 0; i <= 14; i += 2)
		s += setdisp.indexOf(set2.charAt(set1.indexOf(str.charAt(i))));

	return setcontrollo[s % 26];
};

const AltMapping = "LMNPQRSTUV";
const genOmocodie = (input: string): string[] => {
	const substring = input.slice(0, Math.min(input.length, 15));
	const result = [];
	let wrk_string = substring;

	for (let i = substring.length - 1; i >= 0; i--) {
		const char = substring[i];
		if (char && !Number.isNaN(parseInt(char))) {
			const str_arr = wrk_string.split("");
			const charNum = parseInt(char);
			if (charNum > 9) {
				throw new Error("Invalid CF");
			}

			const mappedChar = AltMapping[charNum];
			if (!mappedChar) {
				throw new Error("Invalid CF");
			}

			str_arr[i] = mappedChar;
			wrk_string = str_arr.join("");
			result.push(wrk_string);
		}
	}
	return result;
};
