/**
 * Biblioteca de máscaras compartilhada para formatação de dados
 * Contém funções para formatação de CPF, CNPJ, telefone e outras máscaras comuns
 */

/**
 * Formata um CPF com a máscara XXX.XXX.XXX-XX
 * @param value - Valor a ser formatado
 * @returns CPF formatado
 */
export const formatCPF = (value: string): string => {
  const numbers = value.replace(/\D/g, '');
  if (numbers.length <= 11) {
    return numbers.replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, '$1.$2.$3-$4');
  }
  return numbers.substring(0, 11).replace(/(\d{3})(\d{3})(\d{3})(\d{2})/, '$1.$2.$3-$4');
};

/**
 * Formata um CNPJ com a máscara XX.XXX.XXX/XXXX-XX
 * @param value - Valor a ser formatado
 * @returns CNPJ formatado
 */
export const formatCNPJ = (value: string): string => {
  const numbers = value.replace(/\D/g, '');
  if (numbers.length <= 14) {
    return numbers.replace(/(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})/, '$1.$2.$3/$4-$5');
  }
  return numbers.substring(0, 14).replace(/(\d{2})(\d{3})(\d{3})(\d{4})(\d{2})/, '$1.$2.$3/$4-$5');
};

/**
 * Formata um telefone com a máscara +55 (XX) XXXXX-XXXX ou +55 (XX) XXXX-XXXX
 * @param value - Valor a ser formatado
 * @returns Telefone formatado no padrão brasileiro
 */
export const formatPhone = (value: string): string => {
  const numbers = value.replace(/\D/g, '');
  
  // Se já tem código do país (55), remove para reformatar
  let cleanNumbers = numbers;
  if (numbers.startsWith('55') && numbers.length >= 12) {
    cleanNumbers = numbers.substring(2);
  }
  
  // Formata conforme o tamanho
  if (cleanNumbers.length === 10) {
    // Telefone fixo: +55 (XX) XXXX-XXXX
    return cleanNumbers.replace(/(\d{2})(\d{4})(\d{4})/, '+55 ($1) $2-$3');
  } else if (cleanNumbers.length === 11) {
    // Celular: +55 (XX) XXXXX-XXXX
    return cleanNumbers.replace(/(\d{2})(\d{5})(\d{4})/, '+55 ($1) $2-$3');
  } else if (cleanNumbers.length >= 8) {
    // Tenta formatar com o que tem disponível
    if (cleanNumbers.length <= 10) {
      return cleanNumbers.replace(/(\d{2})(\d{4})(\d{0,4})/, '+55 ($1) $2-$3');
    } else {
      return cleanNumbers.replace(/(\d{2})(\d{5})(\d{0,4})/, '+55 ($1) $2-$3');
    }
  }
  
  // Se não conseguir formatar, retorna com +55 na frente
  return numbers.length > 0 ? `+55 ${numbers}` : numbers;
};

/**
 * Formata um CEP com a máscara XXXXX-XXX
 * @param value - Valor a ser formatado
 * @returns CEP formatado
 */
export const formatCEP = (value: string): string => {
  const numbers = value.replace(/\D/g, '');
  if (numbers.length <= 8) {
    return numbers.replace(/(\d{5})(\d{3})/, '$1-$2');
  }
  return numbers.substring(0, 8).replace(/(\d{5})(\d{3})/, '$1-$2');
};

/**
 * Remove todos os caracteres não numéricos de uma string
 * @param value - Valor a ser limpo
 * @returns String apenas com números
 */
export const removeNonNumeric = (value: string): string => {
  return value.replace(/\D/g, '');
};

/**
 * Valida se um CPF é válido
 * @param cpf - CPF a ser validado
 * @returns true se válido, false caso contrário
 */
export const validateCPF = (cpf: string): boolean => {
  const numbers = removeNonNumeric(cpf);
  
  if (numbers.length !== 11) return false;
  
  // Verifica se todos os dígitos são iguais
  if (/^(\d)\1{10}$/.test(numbers)) return false;
  
  // Validação do primeiro dígito verificador
  let sum = 0;
  for (let i = 0; i < 9; i++) {
    sum += parseInt(numbers[i]) * (10 - i);
  }
  let remainder = sum % 11;
  const digit1 = remainder < 2 ? 0 : 11 - remainder;
  
  if (parseInt(numbers[9]) !== digit1) return false;
  
  // Validação do segundo dígito verificador
  sum = 0;
  for (let i = 0; i < 10; i++) {
    sum += parseInt(numbers[i]) * (11 - i);
  }
  remainder = sum % 11;
  const digit2 = remainder < 2 ? 0 : 11 - remainder;
  
  return parseInt(numbers[10]) === digit2;
};

/**
 * Valida se um CNPJ é válido
 * @param cnpj - CNPJ a ser validado
 * @returns true se válido, false caso contrário
 */
export const validateCNPJ = (cnpj: string): boolean => {
  const numbers = removeNonNumeric(cnpj);
  
  if (numbers.length !== 14) return false;
  
  // Verifica se todos os dígitos são iguais
  if (/^(\d)\1{13}$/.test(numbers)) return false;
  
  // Validação do primeiro dígito verificador
  const weights1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
  let sum = 0;
  for (let i = 0; i < 12; i++) {
    sum += parseInt(numbers[i]) * weights1[i];
  }
  let remainder = sum % 11;
  const digit1 = remainder < 2 ? 0 : 11 - remainder;
  
  if (parseInt(numbers[12]) !== digit1) return false;
  
  // Validação do segundo dígito verificador
  const weights2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
  sum = 0;
  for (let i = 0; i < 13; i++) {
    sum += parseInt(numbers[i]) * weights2[i];
  }
  remainder = sum % 11;
  const digit2 = remainder < 2 ? 0 : 11 - remainder;
  
  return parseInt(numbers[13]) === digit2;
};

/**
 * Valida se um telefone tem formato válido
 * @param phone - Telefone a ser validado
 * @returns true se válido, false caso contrário
 */
export const validatePhone = (phone: string): boolean => {
  const numbers = removeNonNumeric(phone);
  return numbers.length >= 10 && numbers.length <= 11;
};

/**
 * Valida se um CEP tem formato válido
 * @param cep - CEP a ser validado
 * @returns true se válido, false caso contrário
 */
export const validateCEP = (cep: string): boolean => {
  const numbers = removeNonNumeric(cep);
  return numbers.length === 8;
};

/**
 * Valida se um email tem formato válido
 * @param email - Email a ser validado
 * @returns true se válido, false caso contrário
 */
export const validateEmail = (email: string): boolean => {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return emailRegex.test(email);
};

/**
 * Capitaliza a primeira letra de cada palavra
 * @param text - Texto a ser formatado
 * @returns Texto com primeira letra de cada palavra maiúscula
 */
export const capitalizeWords = (text: string): string => {
  return text.toLowerCase().replace(/\b\w/g, l => l.toUpperCase());
};

/**
 * Formata um valor monetário para o padrão brasileiro
 * @param value - Valor a ser formatado
 * @returns Valor formatado como moeda brasileira
 */
export const formatCurrency = (value: number): string => {
  return new Intl.NumberFormat('pt-BR', {
    style: 'currency',
    currency: 'BRL'
  }).format(value);
};

/**
 * Formata uma data para o padrão brasileiro
 * @param date - Data a ser formatada
 * @returns Data formatada como DD/MM/AAAA
 */
export const formatDate = (date: Date | string): string => {
  const dateObj = typeof date === 'string' ? new Date(date) : date;
  return dateObj.toLocaleDateString('pt-BR');
};

/**
 * Formata uma data e hora para o padrão brasileiro
 * @param date - Data a ser formatada
 * @returns Data e hora formatada como DD/MM/AAAA HH:MM
 */
export const formatDateTime = (date: Date | string): string => {
  const dateObj = typeof date === 'string' ? new Date(date) : date;
  return dateObj.toLocaleString('pt-BR');
};