export function digitsOnly(value: string) {
  return String(value || "").replace(/\D/g, "");
}

export function formatCpf(value: string) {
  const digits = digitsOnly(value).slice(0, 11);
  if (digits.length <= 3) return digits;
  if (digits.length <= 6) return digits.replace(/(\d{3})(\d+)/, "$1.$2");
  if (digits.length <= 9) return digits.replace(/(\d{3})(\d{3})(\d+)/, "$1.$2.$3");
  return digits.replace(/(\d{3})(\d{3})(\d{3})(\d+)/, "$1.$2.$3-$4");
}

export function formatCnpj(value: string) {
  const digits = digitsOnly(value).slice(0, 14);
  if (digits.length <= 2) return digits;
  if (digits.length <= 5) return digits.replace(/(\d{2})(\d+)/, "$1.$2");
  if (digits.length <= 8) return digits.replace(/(\d{2})(\d{3})(\d+)/, "$1.$2.$3");
  if (digits.length <= 12) return digits.replace(/(\d{2})(\d{3})(\d{3})(\d+)/, "$1.$2.$3/$4");
  return digits.replace(/(\d{2})(\d{3})(\d{3})(\d{4})(\d+)/, "$1.$2.$3/$4-$5");
}

export function formatDocument(value: string) {
  const digits = digitsOnly(value).slice(0, 14);
  return digits.length <= 11 ? formatCpf(digits) : formatCnpj(digits);
}

export function getDocumentKind(value: string) {
  const digits = digitsOnly(value);
  if (digits.length > 11) return "cnpj";
  if (digits.length > 0) return "cpf";
  return null;
}

export function validateCpf(value: string) {
  const digits = digitsOnly(value);
  if (digits.length !== 11 || /^(\d)\1{10}$/.test(digits)) return false;

  let sum = 0;
  for (let index = 0; index < 9; index += 1) {
    sum += Number(digits[index]) * (10 - index);
  }
  let checker = (sum * 10) % 11;
  if (checker === 10) checker = 0;
  if (checker !== Number(digits[9])) return false;

  sum = 0;
  for (let index = 0; index < 10; index += 1) {
    sum += Number(digits[index]) * (11 - index);
  }
  checker = (sum * 10) % 11;
  if (checker === 10) checker = 0;
  return checker === Number(digits[10]);
}

export function validateCnpj(value: string) {
  const digits = digitsOnly(value);
  if (digits.length !== 14 || /^(\d)\1{13}$/.test(digits)) return false;

  let length = digits.length - 2;
  let numbers = digits.substring(0, length);
  const checkDigits = digits.substring(length);
  let sum = 0;
  let pos = length - 7;

  for (let index = length; index >= 1; index -= 1) {
    sum += Number(numbers.charAt(length - index)) * pos;
    pos -= 1;
    if (pos < 2) pos = 9;
  }

  let result = sum % 11 < 2 ? 0 : 11 - (sum % 11);
  if (result !== Number(checkDigits.charAt(0))) return false;

  length += 1;
  numbers = digits.substring(0, length);
  sum = 0;
  pos = length - 7;

  for (let index = length; index >= 1; index -= 1) {
    sum += Number(numbers.charAt(length - index)) * pos;
    pos -= 1;
    if (pos < 2) pos = 9;
  }

  result = sum % 11 < 2 ? 0 : 11 - (sum % 11);
  return result === Number(checkDigits.charAt(1));
}

export function validateBrazilianDocument(value: string) {
  const digits = digitsOnly(value);
  if (digits.length === 11) return validateCpf(digits);
  if (digits.length === 14) return validateCnpj(digits);
  return false;
}

export function getDocumentLabel(value: string) {
  const digits = digitsOnly(value);
  if (digits.length > 11) return "CNPJ";
  if (digits.length > 0) return "CPF";
  return "CPF ou CNPJ";
}
