import numeral from 'numeral';
import forge from 'node-forge';
import 'numeral/locales/pt-br';

export function maskMoney(number: number, monetary = true) {
  numeral.locale('en');
  let value = numeral(number ? number : 0.0).value();

  numeral.locale('pt-br');

  if (monetary) {
    return numeral(value).format('0,0.00');
  } else {
    return numeral(value).format('0,0.00');
  }
}

export function ucFirst(str: string) {
  // Handle empty or non-string inputs gracefully
  if (!str || typeof str !== 'string') {
    return str;
  }

  str = str.toLowerCase();

  // Capitalize the first character and concatenate with the rest of the string
  return str.charAt(0).toUpperCase() + str.slice(1);
}

export function pad(n: string, width: number, z: string) {
  z = z || '0';
  n = n + '';
  return n.length >= width ? n : new Array(width - n.length + 1).join(z) + n;
}

export function formatarValor(valor: number): string {
  return valor.toLocaleString('pt-BR', {
    style: 'currency',
    currency: 'BRL',
    minimumFractionDigits: 2,
  });
}

export const formatPrice = (value: number): { integerPart: string; decimalPart: string } => {
  const formattedValue = value.toFixed(2);

  const [integerPart, decimalPart] = formattedValue.split('.');

  return { integerPart, decimalPart };
};

export const onlyNumbers = (str: string | undefined) => {
  return str ? str.replace(/[^0-9]/g, '') : '';
}

export function validateDocument(cnpj: any) {

  cnpj = cnpj.replace(/[^\d]+/g, '');

  if (cnpj == '') return false;

  if (cnpj.length != 14)
    return false;

  // Elimina CNPJs invalidos conhecidos
  if (cnpj == "00000000000000" ||
    cnpj == "11111111111111" ||
    cnpj == "22222222222222" ||
    cnpj == "33333333333333" ||
    cnpj == "44444444444444" ||
    cnpj == "55555555555555" ||
    cnpj == "66666666666666" ||
    cnpj == "77777777777777" ||
    cnpj == "88888888888888" ||
    cnpj == "99999999999999")
    return false;

  // Valida DVs
  let tamanho = cnpj.length - 2
  let numeros = cnpj.substring(0, tamanho);
  let digitos = cnpj.substring(tamanho);
  let soma = 0;
  let pos = tamanho - 7;
  let i
  for (i = tamanho; i >= 1; i--) {
    soma += numeros.charAt(tamanho - i) * pos--;
    if (pos < 2)
      pos = 9;
  }
  let resultado = soma % 11 < 2 ? 0 : 11 - soma % 11;
  if (resultado != digitos.charAt(0))
    return false;

  tamanho = tamanho + 1;
  numeros = cnpj.substring(0, tamanho);
  soma = 0;
  pos = tamanho - 7;
  for (i = tamanho; i >= 1; i--) {
    soma += numeros.charAt(tamanho - i) * pos--;
    if (pos < 2)
      pos = 9;
  }
  resultado = soma % 11 < 2 ? 0 : 11 - soma % 11;
  if (resultado != digitos.charAt(1))
    return false;

  return true;
}

export function validateCPF(cpf: any) {
  cpf = cpf.replace(/[^\d]+/g, '');

  if (cpf.length !== 11 || /^(\d)\1+$/.test(cpf)) {
    return false;
  }

  let soma;
  let resto;
  soma = 0;

  for (let i = 1; i <= 9; i++) {
    soma += parseInt(cpf.substring(i - 1, i)) * (11 - i);
  }

  resto = (soma * 10) % 11;
  if (resto === 10 || resto === 11) resto = 0;
  if (resto !== parseInt(cpf.substring(9, 10))) return false;

  soma = 0;

  for (let i = 1; i <= 10; i++) {
    soma += parseInt(cpf.substring(i - 1, i)) * (12 - i);
  }

  resto = (soma * 10) % 11;
  if (resto === 10 || resto === 11) resto = 0;
  if (resto !== parseInt(cpf.substring(10, 11))) return false;

  return true;
}

export function formatDocumento(value = '') {
  const documento = value.replace(/\D/g, '');

  if (documento.length === 11) {
    return value.replace(/(\d{3})(\d{3})(\d{3})(\d{2})/g, '$1.$2.$3-$4');
  } else {
    return value.replace(/(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})/g, '$1.$2.$3/$4-$5');
  }
}


export function formatPhoneNumber(v: string) {

  let r = v.replace(/\D/g, "");
  r = r.replace(/^0/, "");

  if (r.length > 11) {
    r = r.substring(0, 11);
  }

  if (r.length === 11) {
    r = r.replace(/^(\d{2})(\d{5})(\d{4})$/, "($1) $2-$3");
  
  } else if (r.length === 10) {
    r = r.replace(/^(\d{2})(\d{4})(\d{4})$/, "($1) $2-$3");
  
  } else if (r.length > 2) {
    r = r.replace(/^(\d{2})(\d{0,5})/, "($1) $2");
  
  } else if (v.trim() !== "") {
    r = r.replace(/^(\d*)/, "($1");
  }
  
  return r;
}

export function formatPhoneNumberClinicAccredited(v: string) {

  let r = v.replace(/\D/g, ""); 

  r = r.replace(/^0/, "");

  if (r.length === 11) {
    return r.replace(/^(\d{2})(\d{5})(\d{4})$/, "($1) $2-$3");
  }

  if (r.length === 10) {
    return r.replace(/^(\d{2})(\d{4})(\d{4})$/, "($1) $2-$3");
  }

  if (r.length === 9) {
    return r.replace(/^(\d{5})(\d{4})$/, "$1-$2");
  }

  if (r.length === 8) {
    return r.replace(/^(\d{4})(\d{4})$/, "$1-$2");
  }

  if (r.length > 2 && r.length <= 6) {
    return r.replace(/^(\d{2})(\d{0,4})$/, "($1) $2");
  }

  if (r.length <= 2 && r.length > 0) {
    return r.replace(/^(\d{0,2})$/, "($1");
  }

  return r;
}

export function isValidDate(dateString: string) {
  // Verifica o formato da data: "yyyy-mm-dd"
  const regex = /^\d{4}-\d{2}-\d{2}$/;
  if (!dateString.match(regex)) return false;

  // Tenta criar um objeto Date a partir da string
  const date = new Date(dateString);

  // Verifica se a data criada é inválida
  if (isNaN(date.getTime())) return false;

  // Divide a string em partes (ano, mês e dia)
  const [year, month, day] = dateString.split('-').map(Number);

  // Verifica se o ano, mês e dia são consistentes
  return date.getUTCFullYear() === year &&
    date.getUTCMonth() + 1 === month &&
    date.getUTCDate() === day;
}

export const inputMask = (value: string, element: string, onlyNumbers = true) => {
  let data = value.replace(/\.|-|\/|\s|\(|\)/g, '');

  if (onlyNumbers) {
    data = data.replace(/[^\d]/g, '');
  }

  if (element === 'cep') {
    data = data.substr(0, 8);
    data = data.replace(/^(\d{2})(\d{3})(\d{3})/g, '$1$2-$3')
  }

  if (element === 'telefone') {
    data = data.substr(0, 11);

    if (data.length <= 11) {
      data = data.replace(/^([0-9]{2})([0-9]{4,5})([0-9]{4})$/, '($1) $2-$3')
    }
  }

  if (element === 'cpf') {
    data = data.substr(0, 11);

    data = data.replace(/^(\d{3})(\d{3})(\d{3})(\d{2})/g, '$1.$2.$3-$4');
  }

  if (element === 'cnpj') {
    data = data.substr(0, 14);

    data = data.replace(/^(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})/g, '$1.$2.$3/$4-$5');
  }

  if (element === 'mesAno') {
    data = data.replace(/^(\d{2})(\d{1,4})/g, '$1/$2');
  }

  if (element === 'dia') {
    data = data.substr(0, 2);
    data = data.replace(/^(\d{2})$/, '$1');
  }

  if (element === 'mes') {
    data = data.substr(0, 2);
    data = data.replace(/^(\d{2})$/, '$1');
  }

  if (element === 'ano') {
    data = data.substr(0, 4);
    data = data.replace(/^(\d{4})$/, '$1');
  }

  if (element === 'cvv') {
    data = data.replace(/^(\d{3,4})+?$/, '$1');
  }

  return data;
}

export function baixarPdfBase64(arquivos: { base64: string; nome?: string }[]) {
  arquivos.forEach((arquivo, index) => {
    if (!arquivo.base64) {
      console.warn(`Arquivo ${index + 1} inválido: base64 vazio`);
      return;
    }

    // Remove prefixo, se existir
    const base64Data = arquivo.base64.split(",").pop() || arquivo.base64;

    // Converte base64 → bytes
    const byteCharacters = atob(base64Data);
    const byteNumbers = new Array(byteCharacters.length);
    for (let i = 0; i < byteCharacters.length; i++) {
      byteNumbers[i] = byteCharacters.charCodeAt(i);
    }

    const byteArray = new Uint8Array(byteNumbers);
    const blob = new Blob([byteArray], { type: "application/pdf" });
    const blobUrl = URL.createObjectURL(blob);

    // Gera nome dinâmico
    const nomeArquivo = arquivo.nome || `boleto_${index + 1}.pdf`;

    // Cria link temporário para download
    const link = document.createElement("a");
    link.href = blobUrl;
    link.download = nomeArquivo;
    document.body.appendChild(link);
    link.click();

    // Limpa
    document.body.removeChild(link);
    URL.revokeObjectURL(blobUrl);
  });
}

export function decryptAes256Gcm(tokenHex: string, password: string): string | undefined {
  try {
    // Converte HEX → bytes
    const raw = forge.util.hexToBytes(tokenHex.trim());

    // Validação básica do tamanho mínimo
    if (raw.length < 29) throw new Error('Token muito pequeno');

    // iv = 12 bytes, tag = 16 bytes, resto = ciphertext
    const iv = raw.slice(0, 12);
    const tag = raw.slice(12, 28);
    const ciphertext = raw.slice(28);

    // Deriva chave SHA-256
    const md = forge.md.sha256.create();
    md.update(password);
    const key = md.digest().getBytes();

    // Descriptografa
    const decipher = forge.cipher.createDecipher('AES-GCM', key);
    decipher.start({ iv, tag: forge.util.createBuffer(tag) });
    decipher.update(forge.util.createBuffer(ciphertext));
    const pass = decipher.finish();

    if (pass) {
      return decipher.output.toString();
    } else {
      throw new Error('Falha na verificação do authentication tag');
    }
  } catch (error) {
    console.error('Erro ao descriptografar:', error);
  }
}

export function limitarHTML(html: string, limite: number) {

  const textoSemTags = html.replace(/<[^>]+>/g, '');

  const textoLimitado = textoSemTags.substring(0, limite) + (textoSemTags.length > limite ? '...' : '');

  return textoLimitado;
};
