false, 'ERROR' => 'method_not_allowed'], 405); } $channelId = (int) ($_GET['ChannelID'] ?? 0); $limit = min(max((int) ($_GET['Limit'] ?? 50), 1), 200); $before = isset($_GET['Before']) ? (int) $_GET['Before'] : null; $after = isset($_GET['After']) ? (int) $_GET['After'] : null; if ($channelId <= 0) jsonResponse(['OK' => false, 'ERROR' => 'channel_id_required']); // Verify channel exists $channel = queryOne("SELECT ID FROM Hub_Channels WHERE ID = ?", [$channelId]); if (!$channel) jsonResponse(['OK' => false, 'ERROR' => 'channel_not_found']); // Build query $sql = "SELECT * FROM Hub_Messages WHERE ChannelID = ? AND IsDeleted = 0 AND ParentID IS NULL"; $params = [$channelId]; if ($before !== null) { $sql .= " AND ID < ?"; $params[] = $before; } if ($after !== null) { $sql .= " AND ID > ?"; $params[] = $after; } if ($after !== null) { $sql .= " ORDER BY ID ASC LIMIT ?"; } else { $sql .= " ORDER BY ID DESC LIMIT ?"; } $params[] = $limit + 1; // fetch one extra to determine HasMore $rows = queryTimed($sql, $params); $hasMore = count($rows) > $limit; if ($hasMore) array_pop($rows); // If we used ASC (After), reverse for consistent newest-first output if ($after !== null) { $rows = array_reverse($rows); } $messages = []; foreach ($rows as $row) { // Get reply count for each root message $replyCount = queryOne( "SELECT COUNT(*) as cnt FROM Hub_Messages WHERE ParentID = ? AND IsDeleted = 0", [(int) $row['ID']] ); $messages[] = [ 'ID' => (int) $row['ID'], 'ChannelID' => (int) $row['ChannelID'], 'SenderAddress' => $row['SenderAddress'], 'Content' => $row['Content'], 'ParentID' => null, 'IsEdited' => (bool) $row['IsEdited'], 'ReplyCount' => (int) ($replyCount['cnt'] ?? 0), 'CreatedAt' => toISO8601($row['CreatedAt']), 'UpdatedAt' => toISO8601($row['UpdatedAt']), ]; } jsonResponse([ 'OK' => true, 'Messages' => $messages, 'HasMore' => $hasMore, ]);