/**
 * Validadores e formatadores centralizados — AgenciaPsi
 *
 * Nomenclatura alinhada ao schema do banco:
 *   nome_completo, cpf, cpf_responsavel, telefone, telefone_alternativo,
 *   telefone_parente, telefone_responsavel, email_principal, email_alternativo, cep
 *
 * Regra do banco: CPF é armazenado como 11 dígitos (sem máscara).
 *                 Telefones são armazenados como dígitos apenas.
 */

// ─── Utilidade base ────────────────────────────────────────────────────────────

/** Remove tudo que não for dígito */
export function digitsOnly(v) {
  return String(v ?? '').replace(/\D/g, '')
}

// ─── CPF ───────────────────────────────────────────────────────────────────────

/**
 * Valida CPF (com ou sem máscara).
 * Retorna false para sequências repetidas (111.111.111-11) e para dígitos inválidos.
 */
export function isValidCPF(v) {
  const d = digitsOnly(v)
  if (d.length !== 11) return false
  if (/^(\d)\1+$/.test(d)) return false // sequências iguais

  const calcDV = (base) => {
    let sum = 0
    for (let i = 0; i < base.length; i++) sum += Number(base[i]) * (base.length + 1 - i)
    const mod = sum % 11
    return mod < 2 ? 0 : 11 - mod
  }

  const dv1 = calcDV(d.slice(0, 9))
  if (Number(d[9]) !== dv1) return false

  const dv2 = calcDV(d.slice(0, 10))
  if (Number(d[10]) !== dv2) return false

  return true
}

/** Formata CPF para exibição: 000.000.000-00 */
export function fmtCPF(v) {
  const d = digitsOnly(v).slice(0, 11)
  if (!d) return ''
  return d
    .replace(/^(\d{3})(\d)/, '$1.$2')
    .replace(/^(\d{3})\.(\d{3})(\d)/, '$1.$2.$3')
    .replace(/\.(\d{3})(\d)/, '.$1-$2')
}

/** Gera um CPF válido (útil para testes/seed) */
export function generateCPF() {
  const randInt = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min
  const n = Array.from({ length: 9 }, () => randInt(0, 9))

  const calcDV = (base) => {
    let sum = 0
    for (let i = 0; i < base.length; i++) sum += base[i] * (base.length + 1 - i)
    const mod = sum % 11
    return mod < 2 ? 0 : 11 - mod
  }

  const d1 = calcDV(n)
  const d2 = calcDV([...n, d1])
  const cpf = [...n, d1, d2].join('')

  if (/^(\d)\1+$/.test(cpf)) return generateCPF()
  return cpf
}

// ─── CNPJ ──────────────────────────────────────────────────────────────────────

/**
 * Valida CNPJ (com ou sem máscara).
 * Rejeita sequências repetidas (00.000.000/0000-00).
 */
export function isValidCNPJ(v) {
  const d = digitsOnly(v)
  if (d.length !== 14) return false
  if (/^(\d)\1+$/.test(d)) return false

  const calcDV = (base, weights) => {
    let sum = 0
    for (let i = 0; i < base.length; i++) sum += Number(base[i]) * weights[i]
    const mod = sum % 11
    return mod < 2 ? 0 : 11 - mod
  }

  const w1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]
  const w2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2]

  if (Number(d[12]) !== calcDV(d.slice(0, 12), w1)) return false
  if (Number(d[13]) !== calcDV(d.slice(0, 13), w2)) return false

  return true
}

/** Formata CNPJ para exibição: 00.000.000/0000-00 */
export function fmtCNPJ(v) {
  const d = digitsOnly(v).slice(0, 14)
  if (!d) return ''
  return d
    .replace(/^(\d{2})(\d)/, '$1.$2')
    .replace(/^(\d{2})\.(\d{3})(\d)/, '$1.$2.$3')
    .replace(/\.(\d{3})(\d)/, '.$1/$2')
    .replace(/(\d{4})(\d)/, '$1-$2')
}

// ─── RG ────────────────────────────────────────────────────────────────────────

/** Formata RG para exibição: 00.000.000-0 */
export function fmtRG(v) {
  if (!v) return ''
  const d = digitsOnly(v).slice(0, 9)
  if (!d) return ''
  return d
    .replace(/^(\d{2})(\d)/, '$1.$2')
    .replace(/^(\d{2})\.(\d{3})(\d)/, '$1.$2.$3')
    .replace(/\.(\d{3})(\d)/, '.$1-$2')
}

// ─── Telefone ──────────────────────────────────────────────────────────────────

/**
 * Valida telefone brasileiro (com ou sem máscara, com ou sem DDD).
 * Aceita 10 dígitos (fixo) ou 11 dígitos (celular).
 */
export function isValidPhone(v) {
  const d = digitsOnly(v)
  return d.length === 10 || d.length === 11
}

/**
 * Formata telefone para exibição.
 * 11 dígitos → (XX) XXXXX-XXXX (celular)
 * 10 dígitos → (XX) XXXX-XXXX  (fixo)
 */
export function fmtPhone(v) {
  const d = digitsOnly(v)
  if (!d) return ''
  if (d.length === 11) return d.replace(/^(\d{2})(\d{5})(\d{4})$/, '($1) $2-$3')
  if (d.length === 10) return d.replace(/^(\d{2})(\d{4})(\d{4})$/, '($1) $2-$3')
  return d
}

// ─── Email ─────────────────────────────────────────────────────────────────────

/** Valida email (formato básico) */
export function isValidEmail(v) {
  const s = String(v ?? '').trim()
  if (!s) return false
  return /.+@.+\..+/.test(s)
}

// ─── CEP ───────────────────────────────────────────────────────────────────────

/** Valida CEP brasileiro: 8 dígitos */
export function isValidCEP(v) {
  const d = digitsOnly(v)
  return d.length === 8
}

/** Formata CEP para exibição: 00000-000 */
export function fmtCEP(v) {
  const d = digitsOnly(v).slice(0, 8)
  if (!d) return ''
  return d.replace(/^(\d{5})(\d)/, '$1-$2')
}

// ─── Sanitização para o banco ──────────────────────────────────────────────────

/**
 * Converte valor formatado para apenas dígitos antes de salvar no banco.
 * Retorna null para valores vazios.
 */
export function sanitizeDigits(v) {
  const d = digitsOnly(v)
  return d || null
}

/**
 * Converte data de DD/MM/YYYY ou DD-MM-YYYY para YYYY-MM-DD (formato ISO para o banco).
 * Retorna null se inválido.
 */
export function toISODate(v) {
  if (!v) return null
  const s = String(v).trim()
  const match = s.match(/^(\d{2})[/\-](\d{2})[/\-](\d{4})$/)
  if (!match) return null
  const [, dd, mm, yyyy] = match
  const date = new Date(`${yyyy}-${mm}-${dd}`)
  if (isNaN(date.getTime())) return null
  return `${yyyy}-${mm}-${dd}`
}
