bool, 'errors' => array, 'data' => array] */ public static function validateAppointmentData(array $data): array { $errors = []; $validData = []; // Nombre completo if (empty($data['nombre'])) { $errors[] = "Falta el nombre completo"; } elseif (!self::validateFullName($data['nombre'])) { $errors[] = "El nombre debe tener al menos nombre y apellido"; } else { $validData['nombre'] = self::sanitizeName($data['nombre']); } // Documento if (empty($data['documento'])) { $errors[] = "Falta el número de documento"; } elseif (!self::validateDocument($data['documento'])) { $errors[] = "El documento debe tener entre 6 y 11 dígitos"; } else { $validData['documento'] = self::sanitizeDocument($data['documento']); } // Dirección if (empty($data['direccion'])) { $errors[] = "Falta la dirección completa"; } elseif (strlen($data['direccion']) < 10) { $errors[] = "La dirección debe ser más específica (mínimo 10 caracteres)"; } else { $validData['direccion'] = trim($data['direccion']); } // Teléfono if (empty($data['telefono'])) { $errors[] = "Falta el número de celular"; } elseif (!self::validatePhone($data['telefono'])) { $errors[] = "El número de celular debe tener 10 dígitos y comenzar con 3"; } else { $validData['telefono'] = self::sanitizePhone($data['telefono']); } // Email if (empty($data['email'])) { $errors[] = "Falta el correo electrónico"; } elseif (!self::validateEmail($data['email'])) { $errors[] = "El correo electrónico no es válido"; } else { $validData['email'] = strtolower(trim($data['email'])); } // Tipo (particular/seguro) if (empty($data['tipo'])) { $errors[] = "Falta indicar si es particular o por seguro"; } else { $tipo = strtolower(trim($data['tipo'])); if (strpos($tipo, 'particular') !== false) { $validData['tipo'] = 'particular'; } elseif (strpos($tipo, 'seguro') !== false || strpos($tipo, 'eps') !== false) { $validData['tipo'] = 'seguro'; // Extraer nombre del seguro si lo menciona $validData['nombre_seguro'] = self::extractInsuranceName($data['tipo']); } else { $errors[] = "Debe indicar 'particular' o 'seguro'"; } } return [ 'valid' => empty($errors), 'errors' => $errors, 'data' => $validData ]; } /** * Valida un nombre completo * @param string $name * @return bool */ public static function validateFullName(string $name): bool { $name = trim($name); // Debe tener al menos 2 palabras $words = preg_split('/\s+/', $name); if (count($words) < 2) { return false; } // Solo debe contener letras y espacios return preg_match('/^[a-záéíóúñA-ZÁÉÍÓÚÑ\s]+$/u', $name); } /** * Valida un número de documento * @param string $document * @return bool */ public static function validateDocument(string $document): bool { $doc = preg_replace('/[^0-9]/', '', $document); $length = strlen($doc); return $length >= 6 && $length <= 11; } /** * Valida un número de teléfono colombiano * @param string $phone * @return bool */ public static function validatePhone(string $phone): bool { $phone = preg_replace('/[^0-9]/', '', $phone); // Debe tener 10 dígitos y comenzar con 3 return strlen($phone) === 10 && $phone[0] === '3'; } /** * Valida un correo electrónico * @param string $email * @return bool */ public static function validateEmail(string $email): bool { return filter_var($email, FILTER_VALIDATE_EMAIL) !== false; } /** * Sanitiza un nombre * @param string $name * @return string */ public static function sanitizeName(string $name): string { // Convertir a formato título (Primera Letra Mayúscula) $name = mb_convert_case(trim($name), MB_CASE_TITLE, 'UTF-8'); // Remover espacios extras $name = preg_replace('/\s+/', ' ', $name); return $name; } /** * Sanitiza un documento * @param string $document * @return string */ public static function sanitizeDocument(string $document): string { return preg_replace('/[^0-9]/', '', $document); } /** * Sanitiza un teléfono * @param string $phone * @return string */ public static function sanitizePhone(string $phone): string { $phone = preg_replace('/[^0-9]/', '', $phone); // Si tiene 13 dígitos y empieza con 57, quitar el 57 if (strlen($phone) === 12 && substr($phone, 0, 2) === '57') { $phone = substr($phone, 2); } return $phone; } /** * Extrae el nombre del seguro del texto * @param string $text * @return string|null */ private static function extractInsuranceName(string $text): ?string { $insurances = [ 'colsanitas' => 'Colsanitas', 'sanitas' => 'Sanitas', 'sura' => 'Sura', 'compensar' => 'Compensar', 'salud total' => 'Salud Total', 'famisanar' => 'Famisanar', 'nueva eps' => 'Nueva EPS', 'coomeva' => 'Coomeva' ]; $textLower = strtolower($text); foreach ($insurances as $key => $name) { if (strpos($textLower, $key) !== false) { return $name; } } return null; } /** * Parsea datos del paciente desde un mensaje de texto * @param string $message * @return array */ public static function parsePatientDataFromMessage(string $message): array { $data = []; // Dividir por líneas $lines = explode("\n", $message); foreach ($lines as $line) { $line = trim($line); if (empty($line)) { continue; } // Detectar nombre (primera línea larga con letras) if (empty($data['nombre']) && preg_match('/^[a-záéíóúñA-ZÁÉÍÓÚÑ\s]{5,}$/u', $line)) { $data['nombre'] = $line; continue; } // Detectar documento (números de 6-11 dígitos) if (empty($data['documento']) && preg_match('/(\d{6,11})/', $line, $matches)) { $data['documento'] = $matches[1]; continue; } // Detectar teléfono (10 dígitos comenzando con 3) if (empty($data['telefono']) && preg_match('/(3\d{9})/', $line, $matches)) { $data['telefono'] = $matches[1]; continue; } // Detectar email if (empty($data['email']) && preg_match('/([a-zA-Z0-9._-]+@[a-zA-Z0-9._-]+\.[a-zA-Z]+)/', $line, $matches)) { $data['email'] = $matches[1]; continue; } // Detectar dirección (contiene calle, carrera, etc.) if (empty($data['direccion']) && preg_match('/(calle|carrera|cra|cl|diagonal|transversal|avenida|av)/i', $line)) { $data['direccion'] = $line; continue; } // Detectar tipo (particular/seguro) if (empty($data['tipo']) && preg_match('/(particular|seguro|eps)/i', $line)) { $data['tipo'] = $line; continue; } } return $data; } /** * Genera un mensaje con los errores de validación * @param array $errors * @return string */ public static function formatValidationErrors(array $errors): string { $message = "⚠️ Por favor corrige los siguientes datos:\n\n"; foreach ($errors as $error) { $message .= "❌ $error\n"; } $message .= "\nEnvía la información completa de nuevo."; return $message; } /** * Genera un resumen de los datos validados * @param array $data * @return string */ public static function formatDataSummary(array $data): string { $message = "📋 DATOS RECIBIDOS:\n\n"; $message .= "👤 Nombre: {$data['nombre']}\n"; $message .= "🆔 Documento: {$data['documento']}\n"; $message .= "📍 Dirección: {$data['direccion']}\n"; $message .= "📱 Teléfono: {$data['telefono']}\n"; $message .= "📧 Email: {$data['email']}\n"; $message .= "💳 Tipo: {$data['tipo']}"; if (isset($data['nombre_seguro'])) { $message .= " ({$data['nombre_seguro']})"; } $message .= "\n\n¿Los datos son correctos?\nResponde: *SÍ* o *NO*"; return $message; } }