} */ $botName = trim($_GET['BotName'] ?? ''); $status = trim($_GET['Status'] ?? ''); $channel = trim($_GET['Channel'] ?? ''); $assignedBy = trim($_GET['AssignedBy'] ?? ''); $since = trim($_GET['Since'] ?? ''); $limit = min(max((int) ($_GET['Limit'] ?? 100), 1), 500); $offset = max((int) ($_GET['Offset'] ?? 0), 0); $validStatuses = ['active', 'paused', 'done', 'cancelled']; try { $where = []; $params = []; if ($botName !== '') { $where[] = "BotName = ?"; $params[] = $botName; } if ($status !== '') { if (!in_array($status, $validStatuses, true)) { http_response_code(400); apiAbort(['OK' => false, 'ERROR' => 'Invalid status filter']); } $where[] = "Status = ?"; $params[] = $status; } if ($channel !== '') { $where[] = "Channel = ?"; $params[] = $channel; } if ($assignedBy !== '') { $where[] = "AssignedBy = ?"; $params[] = $assignedBy; } if ($since !== '') { // Validate date format if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $since)) { http_response_code(400); apiAbort(['OK' => false, 'ERROR' => 'Since must be YYYY-MM-DD']); } $where[] = "StartedOn >= ?"; $params[] = $since . ' 00:00:00'; } $whereClause = empty($where) ? '' : 'WHERE ' . implode(' AND ', $where); // Get total count $countRow = queryOne("SELECT COUNT(*) AS Total FROM TeamTasks $whereClause", $params); $total = (int) ($countRow['Total'] ?? 0); // Get paginated results $params[] = $limit; $params[] = $offset; $tasks = queryTimed(" SELECT ID, BotName, Title, Status, Channel, StartedOn, PausedOn, CompletedOn, Notes, AssignedBy FROM TeamTasks $whereClause ORDER BY StartedOn DESC LIMIT ? OFFSET ? ", $params); jsonResponse(['OK' => true, 'Tasks' => $tasks, 'Total' => $total]); } catch (Throwable $e) { http_response_code(500); apiAbort(['OK' => false, 'ERROR' => 'Failed to fetch tasks: ' . $e->getMessage()]); }