/**
 * A regra do cadastro de fornecedor, num lugar so.
 *
 * Antes ela morava duplicada: a tela decidia se o botao ficava cinza
 * (`canSubmit`, com quatro condicoes) e a rota decidia de novo com as mesmas
 * quatro. As duas exigiam CNPJ com 14 digitos e e-mail preenchido, e nenhuma
 * das duas dizia o que faltava. O resultado esta no banco: 14 dos 53
 * fornecedores tem e-mail sem arroba e 2 tem CNPJ com quatorze zeros. As
 * pessoas inventaram dado para destravar o botao.
 *
 * A regra nova, decidida em 09/09/2026: nome, documento e pelo menos um
 * contato. O documento aceita CNPJ ou CPF e e conferido pelo digito
 * verificador de verdade, nao pela contagem de digitos.
 */

/* Extensao explicita: e o que o runner de teste do Node exige para resolver o
   modulo. O bundler do Next aceita as duas formas. */
import { validateCNPJ, validateCPF, maskCNPJ, maskCPF } from "../document-utils.ts";

export type TipoDeDocumento = "cnpj" | "cpf";

export type RascunhoDoFornecedor = {
  nome: string;
  documento: string;
  email: string;
  telefone: string;
};

export type Recusa = {
  campo: "nome" | "documento" | "contato" | "email" | "telefone";
  mensagem: string;
};

export function apenasDigitos(valor: unknown) {
  return String(valor ?? "").replace(/\D/g, "");
}

/**
 * Onze digitos so pode ser CPF; qualquer outro tamanho e tratado como CNPJ.
 * Isso decide a mascara enquanto a pessoa digita, entao precisa responder
 * mesmo com o campo pela metade.
 */
export function tipoDoDocumento(valor: unknown): TipoDeDocumento {
  return apenasDigitos(valor).length === 11 ? "cpf" : "cnpj";
}

export function formatarDocumento(valor: unknown) {
  const digitos = apenasDigitos(valor).slice(0, 14);
  return digitos.length <= 11 ? maskCPF(digitos) : maskCNPJ(digitos);
}

export function documentoValido(valor: unknown) {
  const digitos = apenasDigitos(valor);
  if (digitos.length === 11) return validateCPF(digitos);
  if (digitos.length === 14) return validateCNPJ(digitos);
  return false;
}

/**
 * Formato de e-mail, nao existencia. O objetivo e barrar "aa" e "teste", que
 * e o que aparece no banco hoje, sem inventar regra que recuse endereco
 * valido esquisito.
 */
export function emailValido(valor: unknown) {
  const texto = String(valor ?? "").trim();
  if (!texto || /\s/.test(texto)) return false;
  return /^[^@]+@[^@.]+(\.[^@.]+)+$/.test(texto);
}

/** Fixo com DDD tem 10 digitos; celular tem 11. */
export function telefoneValido(valor: unknown) {
  const digitos = apenasDigitos(valor);
  return digitos.length === 10 || digitos.length === 11;
}

export function formatarTelefone(valor: unknown) {
  const d = apenasDigitos(valor).slice(0, 11);
  if (d.length <= 2) return d ? `(${d}` : "";
  if (d.length <= 6) return `(${d.slice(0, 2)}) ${d.slice(2)}`;
  if (d.length <= 10) return `(${d.slice(0, 2)}) ${d.slice(2, 6)}-${d.slice(6)}`;
  return `(${d.slice(0, 2)}) ${d.slice(2, 7)}-${d.slice(7)}`;
}

/**
 * A checagem inteira, na ordem em que a pessoa preenche.
 *
 * `documentoJaGravado` existe por causa dos cadastros antigos: quem abrir um
 * fornecedor gravado com CNPJ invalido para arrumar o telefone nao pode ser
 * barrado pelo documento que ele nao esta mexendo. Se o documento continua
 * exatamente o mesmo, passa; se mudou, e conferido.
 */
export function conferirFornecedor(
  rascunho: RascunhoDoFornecedor,
  opcoes?: { documentoJaGravado?: string }
): Recusa | null {
  if (!String(rascunho.nome ?? "").trim()) {
    return { campo: "nome", mensagem: "Informe o nome do fornecedor." };
  }

  const documento = apenasDigitos(rascunho.documento);
  if (!documento) {
    return { campo: "documento", mensagem: "Informe o CNPJ ou o CPF do fornecedor." };
  }

  const gravado = apenasDigitos(opcoes?.documentoJaGravado);
  const naoMexeuNoDocumento = Boolean(gravado) && gravado === documento;

  if (!naoMexeuNoDocumento && !documentoValido(documento)) {
    return {
      campo: "documento",
      mensagem:
        documento.length === 11
          ? "Esse CPF não existe. Confira os números."
          : "Esse CNPJ não existe. Confira os números.",
    };
  }

  const email = String(rascunho.email ?? "").trim();
  const telefone = apenasDigitos(rascunho.telefone);

  if (!email && !telefone) {
    return {
      campo: "contato",
      mensagem: "Informe pelo menos um contato: telefone ou e-mail.",
    };
  }

  if (email && !emailValido(email)) {
    return { campo: "email", mensagem: "Esse e-mail não parece completo." };
  }

  if (telefone && !telefoneValido(telefone)) {
    return { campo: "telefone", mensagem: "O telefone precisa ter DDD e o número completo." };
  }

  return null;
}
