import { useI18n } from "vue-i18n";

/**
 * @description Checa a moeda selecionada.
 * @param {number} moeda moeda selecionada.
 * @returns {object} opções de moeda.
 */
const checaMoeda = (moeda) => {
  let currencyOptions = {};

  if (moeda == 1) {
    currencyOptions = {
      locale: "pt-BR",
      currency: "BRL",
      currencyDisplay: "symbol",

      hideCurrencySymbolOnFocus: false,
      hideGroupingSeparatorOnFocus: false,
      hideNegligibleDecimalDigitsOnFocus: false,
      autoDecimalDigits: true,
      useGrouping: true,
      accountingSign: false,
    };
  } else if (moeda == 2) {
    currencyOptions = {
      currency: "PYG",
      locale: "es-PY",
      valueAsInteger: true,
      distractionFree: true,
      precision: 0,
      autoDecimalMode: true,

      valueRange: { min: 0 },

      allowNegative: true,
    };
  } else if (moeda == 3) {
    currencyOptions = {
      locale: "en-US",
      currency: "USD",
      currencyDisplay: "symbol",

      hideCurrencySymbolOnFocus: true,
      hideGroupingSeparatorOnFocus: true,
      hideNegligibleDecimalDigitsOnFocus: false,
      autoDecimalDigits: true,
      useGrouping: true,
      accountingSign: false,
    };
  }

  return currencyOptions;
};

/**
 * @description Corta uma string em um determinado tamanho.
 * @param {string} string string a ser cortada.
 * @param {string} size tamanho da string.
 * @returns {string} string cortada.
 */
const excerpt = (string, size = 30) => {
  if (size == null) return string;

  if (string.length > size) {
    string = string.substring(0, size) + "...";
  }

  return string;
};

// formatters

// formatters de data e hora

/**
 * @description Converte uma data e hora para o formato brasileiro.
 * @param {string} dateTimeString data e hora.
 * @returns {string} data e hora no formato brasileiro.
 * @throws {Error} Caso a data seja nula ou invalida.
 * @returns {string} data formatada.
 * @example
 * // convertDateTime("2023-05-23T13:07:27.000000Z");
 * // Output: 23/05/2023 10:07:27
 */
const convertDateTime = (dateTimeString) => {
  const dateTime = new Date(dateTimeString);

  const options = {
    timeZone: "America/Sao_Paulo",
    day: "2-digit",
    month: "2-digit",
    year: "numeric",
    hour: "2-digit",
    minute: "2-digit",
    second: "2-digit",
  };

  const formattedDateTime = dateTime
    .toLocaleString("pt-BR", options)
    .replace(",", "");

  return formattedDateTime;
};

/**
 * @description Formata uma data de DD/MM/YYYY para YYYY-MM-DD
 * @param {string} date data.
 * @param {string} time tempo.
 * @throws {Error} Caso a data seja nula ou invalida.
 * @returns {string} data formatada.
 */
const formatDateDMYtoYMD = (date, time) => {
  if (!date) throw new Error(useI18n().t("validation.rules.required"));

  const testDate =
    /^([0-2][0-9]|(3)[0-1])(\/)(((0)[0-9])|((1)[0-2]))(\/)\d{4}$/;

  if (testDate.test(date) === false)
    throw new Error(useI18n().t("validation.rules.date"));

  const [day, month, year] = date.split("/");

  return `${year}-${month}-${day} ${time ? time : ""}`;
};

/**
 * @description Formata uma data de YYYY-MM-DD para DD/MM/YYYY
 * @param {string} dateTime data e hora.
 * @returns {string} data e hora no formato brasileiro.
 * @example
 * // formatDateYMDtoDMY("2023-05-23T13:07:27.000000Z");
 * // Output: 23/05/2023 10:07:27
 */
const formatDateYMDtoDMY = (dateTime) => {
  const [datePart, timePart] = dateTime.split(" ");

  const [year, month, day] = datePart.split("-");

  const formattedDate = `${day}/${month}/${year}`;

  if (timePart) {
    const [hours, minutes, seconds] = timePart.split(":");

    const formattedTime = `${hours}:${minutes}:${seconds}`;

    return `${formattedDate} ${formattedTime}`;
  }

  return formattedDate;
};

// formatters de moeda e number

/**
 * @description Converte um valor monetário para centavos.
 * @param {number|string|null|undefined} value valor a ser convertido.
 * @returns {number|null} valor convertido em centavos.
 */
const convertToCents = (value) => {
  if (value === null || value === undefined || value === "") return null;

  if (typeof value === "number") {
    return Math.round(value * 100);
  }

  if (typeof value === "string") {
    const cleanValue = value.replace(/[R$\s.]/g, "").replace(",", ".");

    const numericValue = parseFloat(cleanValue);

    return isNaN(numericValue) ? null : Math.round(numericValue * 100);
  }

  return null;
};

/**
 * @description Formata a moeda.
 * @param {number} value valor.
 * @returns {string} valor formatado.
 */
const formatCurrency = (value) => {
  return new Intl.NumberFormat("pt-BR", {
    style: "currency",
    currency: "BRL",
    minimumFractionDigits: 2,
  }).format(Number(value ?? 0));
};

/**
 * @description Formata a moeda de forma compacta.
 * @param {number} value valor.
 * @returns {string} valor formatado.
 */
const formatCurrencyCompact = (value) => {
  return new Intl.NumberFormat("pt-BR", {
    style: "currency",
    currency: "BRL",
    notation: "compact",
    maximumFractionDigits: 1,
  }).format(Number(value ?? 0));
};

/**
 * @description Formata um valor decimal.
 * @param {number} value valor.
 * @returns {string} valor formatado.
 */
const formatDecimal = (value) => {
  return Number(value ?? 0).toLocaleString("pt-BR", {
    minimumFractionDigits: 1,
    maximumFractionDigits: 1,
  });
};

/**
 * @description Formata um valor inteiro.
 * @param {number} value valor.
 * @returns {string} valor formatado.
 */
const formatInteger = (value) => {
  return Number(value ?? 0).toLocaleString("pt-BR");
};

/**
 * @description Formata um valor percentual.
 * @param {number} value valor.
 * @param {number} digits quantidade de casas decimais.
 * @returns {string} valor formatado.
 */
const formatPercent = (value, digits = 2) => {
  return `${Number(value ?? 0)
    .toFixed(digits)
    .replace(".", ",")}%`;
};

// filters

/**
 * @description Filtra a moeda.
 * @param {number} value valor.
 * @returns {string} valor formatado.
 */
const filterCurrency = (value) => {
  if (value) {
    value = parseFloat(value);

    return value.toLocaleString("pt-BR", {
      style: "currency",
      currency: "BRL",
    });
  }

  return value;
};

/**
 * @description Filtra a unidade de medida.
 * @param {number} value valor.
 * @returns {string} valor formatado.
 */
const filterUnidadeMedida = (value) => {
  return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ".");
};

// validators

/**
 * @description Valida se a data é válida.
 * @param {string} date data.
 * @returns {boolean} true se a data é válida, false caso contrário.
 */
const validaData = (date) => {
  const regex = /^(0[1-9]|[12][0-9]|3[01])\/(0[1-9]|1[0-2])\/\d{4}$/;

  return regex.test(date);
};

/**
 * @description Valida se a hora é válida.
 * @param {string} time hora.
 * @returns {boolean} true se a hora é válida, false caso contrário.
 */
const validaHora = (time) => {
  const regex = /^([0-1][0-9]|2[0-3]):[0-5][0-9]$/;

  return regex.test(time);
};

/**
 * @description Valida se a data e hora são válidas.
 * @param {string} dataHora data e hora.
 * @returns {boolean} true se a data e hora são válidas, false caso contrário.
 */
const validaDataHora = (dataHora) => {
  const regex =
    /^(0[1-9]|[12][0-9]|3[01])\/(0[1-9]|1[0-2])\/\d{4}\s([0-1][0-9]|2[0-3]):[0-5][0-9]$/;

  return regex.test(dataHora);
};

// outros

/**
 * @description Trunca o nome de um arquivo preservando a extensão.
 * @param {string} name nome do arquivo.
 * @returns {string} nome truncado.
 */
const truncatedName = (name) => {
  if (name.length <= 15) return name;

  const extension = name.split(".").pop();
  const nameWithoutExt = name.substring(0, name.lastIndexOf("."));

  return `${nameWithoutExt.substring(0, 8)}...${extension}`;
};

/**
 * Mascara um número de CPF, exibindo apenas os três primeiros e os dois últimos dígitos.
 * A função lida com CPFs formatados (ex: '123.456.789-00') ou apenas com números.
 *
 * @param {string | null | undefined} cpf O CPF a ser mascarado.
 * @returns {string} O CPF mascarado (ex: '123.***.***-00') ou uma string vazia se a entrada for inválida.
 *
 * @example
 * maskCpf("12345678900"); // '123.***.***-00'
 * maskCpf("123.456.789-00"); // '123.***.***-00'
 * maskCpf(null); // ''
 */
export const maskCpf = (cpf) => {
  if (!cpf) {
    return "";
  }

  const cleanedCpf = String(cpf).replace(/\D/g, "");

  if (cleanedCpf.length !== 11) {
    console.warn(
      "CPF inválido fornecido para a máscara. Retornando valor original.",
    );

    return cpf;
  }

  const firstPart = cleanedCpf.slice(0, 3);
  const lastPart = cleanedCpf.slice(9, 11);

  return `${firstPart}.***.***-${lastPart}`;
};

export {
  checaMoeda,
  convertDateTime,
  convertToCents,
  excerpt,
  filterCurrency,
  filterUnidadeMedida,
  formatCurrency,
  formatCurrencyCompact,
  formatDateDMYtoYMD,
  formatDateYMDtoDMY,
  formatDecimal,
  formatInteger,
  formatPercent,
  truncatedName,
  validaData,
  validaDataHora,
  validaHora,
};
