import { z } from "zod";
import { getComuneFromIndex } from "~/i18n/comuni";
import { searchNazioneByIndex } from "~/i18n/nazioni";
import type { ListOption } from "~/components/custom_ui/multiselect";

export const getComuneFieldValue = (
  fieldValue: string,
  comuni_options: string[],
): ListOption | undefined => {
  if (fieldValue !== "") {
    const num = parseInt(fieldValue);
    if (num <= comuni_options.length) {
      return {
        value: String(num),
        label: String(comuni_options[num as keyof typeof comuni_options]),
      };
    }
  }
  return undefined;
};

const getInizialiCF = (stringa: string) => {
  const vocali = ["A", "E", "I", "O", "U"];
  let iniziali = "";
  for (const c of stringa) {
    if (iniziali.length < 3) {
      if (!vocali.includes(c)) {
        iniziali += c;
      }
    }
  }
  if (iniziali.length < 3) {
    for (const c of stringa) {
      if (iniziali.length < 3) {
        if (vocali.includes(c)) {
          iniziali += c;
        }
      }
    }
  }
  if (iniziali.length == 2) {
    iniziali += "X";
  }
  return iniziali;
};

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 AltMapping = "LMNPQRSTUV";
const getAlternativeCF = (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 && !isNaN(parseInt(char))) {
      const str_arr = wrk_string.split("");
      if (parseInt(char) > 9) {
        throw new Error("Invalid CF");
      }
      str_arr[i] = AltMapping[parseInt(char)]!;
      wrk_string = str_arr.join("");
      result.push(wrk_string);
    }
  }
  return result;
};

const genCatasto = ({
  luogoNascita,
  nazioneNascita,
}: {
  luogoNascita: string;
  nazioneNascita: string;
}) => {
  let catasto = "";
  if (nazioneNascita === "0") {
    if (luogoNascita !== "") {
      const comune = getComuneFromIndex(parseInt(luogoNascita));
      if (comune) {
        catasto = comune.CATASTO;
      }
    }
  } else {
    if (nazioneNascita !== "") {
      const nazione = searchNazioneByIndex(parseInt(nazioneNascita));
      if (nazione) {
        catasto = nazione.CATASTO;
      }
    }
  }
  return catasto;
};

const gen15CF = ({
  cognome,
  nome,
  dataNascita,
  sesso,
  luogoNascita,
  nazioneNascita,
}: {
  cognome: string;
  nome: string;
  dataNascita: Date;
  sesso: string;
  luogoNascita: string;
  nazioneNascita: string;
}): string => {
  const data = new Date(dataNascita);

  return `${getInizialiCF(cognome)}${getInizialiCF(nome)}${data.getFullYear().toString().slice(-2)}${getMonthLetterCF(data.getMonth())}${getDayCF(data.getDate(), sesso)}${genCatasto({ luogoNascita, nazioneNascita })}`;
};

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];
};

export const checkFiscalCodeValidity = ({
  path,
  codiceFiscale,
  cognome,
  nome,
  dataNascita,
  sesso,
  refinementContext,
  luogoNascita,
  nazioneNascita,
}: {
  path: string;
  codiceFiscale: string;
  cognome: string;
  nome: string;
  dataNascita: Date;
  sesso: string;
  refinementContext: z.RefinementCtx;
  luogoNascita: string;
  nazioneNascita: string;
}) => {
  const cognomeUpper = cognome.toUpperCase();
  const nomeUpper = nome.toUpperCase();
  const gen = gen15CF({
    cognome: cognomeUpper,
    nome: nomeUpper,
    dataNascita,
    sesso,
    luogoNascita,
    nazioneNascita,
  });
  const control = genCarattereControllo(gen);

  if (
    gen !== codiceFiscale.slice(0, 15) &&
    !(codiceFiscale in getAlternativeCF(gen))
  ) {
    console.log("gen", gen);
    console.log("codiceFiscale", codiceFiscale);
    console.log("alternative", getAlternativeCF(gen));
    refinementContext.addIssue({
      code: z.ZodIssueCode.custom,
      message: "Codice fiscale non valido",
      path: [path],
    });
  }

  if (control !== codiceFiscale.slice(-1)) {
    refinementContext.addIssue({
      code: z.ZodIssueCode.custom,
      message: "Codice di controllo non valido",
      path: [path],
    });
  }

  if (codiceFiscale.length !== 16) {
    refinementContext.addIssue({
      code: z.ZodIssueCode.custom,
      message: "Inserisci un codice fiscale valido",
      path: [path],
    });
  }
  if (
    !/^(?:[A-Z][AEIOU][AEIOUX]|[AEIOU]X{2}|[B-DF-HJ-NP-TV-Z]{2}[A-Z]){2}(?:[\dLMNP-V]{2}(?:[A-EHLMPR-T](?:[04LQ][1-9MNP-V]|[15MR][\dLMNP-V]|[26NS][0-8LMNP-U])|[DHPS][37PT][0L]|[ACELMRT][37PT][01LM]|[AC-EHLMPR-T][26NS][9V])|(?:[02468LNQSU][048LQU]|[13579MPRTV][26NS])B[26NS][9V])(?:[A-MZ][1-9MNP-V][\dLMNP-V]{2}|[A-M][0L](?:[1-9MNP-V][\dLMNP-V]|[0L][1-9MNP-V]))[A-Z]$/i.exec(
      codiceFiscale,
    )
  ) {
    refinementContext.addIssue({
      code: z.ZodIssueCode.custom,
      message: "Inserisci un codice fiscale valido",
      path: [path],
    });
  }

  if (codiceFiscale.slice(0, 3) !== getInizialiCF(cognomeUpper)) {
    refinementContext.addIssue({
      code: z.ZodIssueCode.custom,
      message: "Codice fiscale incompatibile con cognome inserito",
      path: [path],
    });
  }
  if (codiceFiscale.slice(3, 6) !== getInizialiCF(nomeUpper)) {
    refinementContext.addIssue({
      code: z.ZodIssueCode.custom,
      message: "Codice fiscale incompatibile con nome inserito",
      path: [path],
    });
  }

  if (
    codiceFiscale.slice(6, 8) !== dataNascita.getFullYear().toString().slice(-2)
  ) {
    refinementContext.addIssue({
      code: z.ZodIssueCode.custom,
      message: "Codice fiscale incompatibile con anno di nascita",
      path: [path],
    });
  }

  if (codiceFiscale.slice(8, 9) !== getMonthLetterCF(dataNascita.getMonth())) {
    refinementContext.addIssue({
      code: z.ZodIssueCode.custom,
      message: "Codice fiscale incompatibile con mese di nascita",
      path: [path],
    });
  }
  if (codiceFiscale.slice(9, 11) !== getDayCF(dataNascita.getDate(), sesso)) {
    refinementContext.addIssue({
      code: z.ZodIssueCode.custom,
      message: "Codice fiscale incompatibile con giorno di nascita",
      path: [path],
    });
  }
  if (nazioneNascita === "0") {
    if (luogoNascita !== "") {
      const comune = getComuneFromIndex(parseInt(luogoNascita));
      if (comune && codiceFiscale.slice(11, 15) !== comune.CATASTO) {
        refinementContext.addIssue({
          code: z.ZodIssueCode.custom,
          message: "Codice fiscale incompatibile con luogo di nascita",
          path: [path],
        });
      }
    }
  } else {
    if (nazioneNascita !== "") {
      const nazione = searchNazioneByIndex(parseInt(nazioneNascita));
      if (nazione && codiceFiscale.slice(11, 15) !== nazione.CATASTO) {
        refinementContext.addIssue({
          code: z.ZodIssueCode.custom,
          message: "Codice fiscale incompatibile con luogo di nascita",
          path: [path],
        });
      }
    }
  }
};
