false, 'error' => 'user_id requerido']); exit; } $limit = max(1, min(200, intval($_GET['limit'] ?? 50))); $before = !empty($_GET['before']) ? $_GET['before'] : null; $beforeId = !empty($_GET['before_id']) ? intval($_GET['before_id']) : null; $since = !empty($_GET['since']) ? $_GET['since'] : null; $tsRegex = '/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}$/'; if ($before && !preg_match($tsRegex, $before)) { http_response_code(400); echo json_encode(['success' => false, 'error' => 'before inválido']); exit; } if ($since && !preg_match($tsRegex, $since)) { http_response_code(400); echo json_encode(['success' => false, 'error' => 'since inválido']); exit; } $db = Database::getInstance(); $params = ['user_id' => $userId]; $sql = "SELECT c.id, c.user_id, c.content, c.message_id, c.media_url, c.local_file, c.local_thumb, c.filename, c.mime_type, c.direction, c.message_type, c.status, c.created_at, COALESCE(c.is_read, 0) AS is_read, c.reply_to_message_id, c.reaction_emoji, c.reaction_to_message_id, u.phone_number AS user_phone FROM conversations c LEFT JOIN users u ON u.id = c.user_id WHERE c.user_id = :user_id AND c.canal = 'turnero'"; if ($since) { $sql .= " AND c.created_at > :since"; $params['since'] = $since; $sql .= " ORDER BY c.created_at ASC, c.id ASC LIMIT {$limit}"; } else { if ($before) { $sql .= " AND (c.created_at < :before_lt"; $params['before_lt'] = $before; if ($beforeId) { $sql .= " OR (c.created_at = :before_eq AND c.id < :before_id)"; $params['before_eq'] = $before; $params['before_id'] = $beforeId; } $sql .= ")"; } $sql .= " ORDER BY c.created_at DESC, c.id DESC LIMIT {$limit}"; } $rows = $db->fetchAll($sql, $params); if (!$since) { $rows = array_reverse($rows ?: []); } $hasMore = count($rows) === $limit; $earliest = $rows[0]['created_at'] ?? null; $earliestId = $rows[0]['id'] ?? null; $data = array_map(function($m) { $mediaUrl = $m['media_url'] ?? null; $localFile = $m['local_file'] ?? null; $external = null; if ($mediaUrl && !$localFile) { // WhatsApp CDN URLs require Bearer token — always proxy through media-url.php if (preg_match('#^https?://#i', $mediaUrl)) { $external = '/api/version/media-url.php?url=' . urlencode($mediaUrl); } else { $external = '/api/version/media-url.php?id=' . urlencode($mediaUrl); } } return [ 'id' => intval($m['id']), 'user_id' => intval($m['user_id']), 'content' => $m['content'] ?? '', 'message_id' => $m['message_id'] ?? null, 'local_file' => $m['local_file'] ?? null, 'local_thumb' => $m['local_thumb'] ?? null, 'media_url_external' => $external, 'filename' => $m['filename'] ?? null, 'mime_type' => $m['mime_type'] ?? null, 'user_phone' => $m['user_phone'] ?? null, 'direction' => $m['direction'] ?? 'incoming', 'message_type' => $m['message_type'] ?? 'text', 'status' => $m['status'] ?? 'received', 'created_at' => $m['created_at'], 'is_read' => intval($m['is_read']), 'reply_to_message_id' => $m['reply_to_message_id'] ?? null, 'reaction_emoji' => $m['reaction_emoji'] ?? null, 'reaction_to_message_id' => $m['reaction_to_message_id'] ?? null, ]; }, $rows); echo json_encode([ 'success' => true, 'data' => $data, 'has_more' => $hasMore, 'earliest' => $earliest, 'earliest_id' => $earliestId, ], JSON_UNESCAPED_UNICODE); } catch (Exception $e) { error_log('chat_get_messages.php: ' . $e->getMessage()); http_response_code(500); echo json_encode(['success' => false, 'error' => 'Error interno']); }