since_id) $beforeId = (int)($_GET['before_id'] ?? 0); // pour paginer vers le HAUT (id < before_id) $limit = (int)($_GET['limit'] ?? 50); // taille de page (max 100) if ($convId <= 0) json_response(['error' => 'bad_params'], 400); if ($limit <= 0) $limit = 50; if ($limit > 100) $limit = 100; // Vérifie droits et récupère la conversation $conv = assert_conversation_access($pdo, $convId, $role, $meId); // Filtre de visibilité selon le rôle (suppression “pour moi”) $hideCol = ($role === 'praticien') ? 'deleted_for_praticien' : 'deleted_for_client'; // Stratégie de tri: // - On interroge en DESC (plus récents en premier) pour limiter efficacement, // - puis on reverse en PHP pour renvoyer ASC (du plus ancien au plus récent) côté client. $params = [$convId]; $where = "conversation_id = ? AND $hideCol = 0"; $order = "ORDER BY id DESC"; $limitSql = "LIMIT $limit"; if ($sinceId > 0 && $beforeId > 0) { // Cas ambigu — on privilégie since_id (nouveaux messages) $beforeId = 0; } if ($sinceId > 0) { $where .= " AND id > ?"; $params[] = $sinceId; } elseif ($beforeId > 0) { $where .= " AND id < ?"; $params[] = $beforeId; } else { // premier chargement (pas de since/before) → rien à ajouter } $sql = "SELECT id, conversation_id, sender_role, sender_id, body, attachment_path, attachment_name, retracted_for_all, created_at FROM messages WHERE $where $order $limitSql"; $stmt = $pdo->prepare($sql); $stmt->execute($params); $rowsDesc = $stmt->fetchAll(PDO::FETCH_ASSOC); // Transformations + placeholder “(Message supprimé)” $rows = array_reverse($rowsDesc); // renvoyer ASC foreach ($rows as &$m) { $m['id'] = (int)$m['id']; $m['conversation_id'] = (int)$m['conversation_id']; $m['sender_id'] = (int)$m['sender_id']; if (!empty($m['retracted_for_all'])) { $m['body'] = '(' . ($translations['msg_message_supprime'] ?? 'Message supprimé') . ')'; $m['attachment_path'] = null; $m['attachment_name'] = null; } unset($m['retracted_for_all']); } unset($m); // Calcul du “has_more” pour la pagination vers le haut (before_id) $hasMore = false; $nextBeforeId = null; if (!empty($rows)) { // Si on a utilisé beforeId (ou premier load), vérifier s'il reste des messages plus anciens // On prend le plus ancien renvoyé (premier en ASC) et teste s'il existe plus ancien $oldestId = $rows[0]['id']; $stmt2 = $pdo->prepare("SELECT 1 FROM messages WHERE conversation_id = ? AND $hideCol = 0 AND id < ? LIMIT 1"); $stmt2->execute([$convId, $oldestId]); $hasMore = (bool)$stmt2->fetchColumn(); $nextBeforeId = $oldestId; // pour l'appel suivant: before_id = oldestId } json_response([ 'items' => $rows, 'has_more' => $hasMore, 'next_before_id'=> $hasMore ? $nextBeforeId : null, ]);