integer('per_page', 25), 1), 100); $soldOutOnly = $request->boolean('sold_out_only'); $sort = trim((string) $request->query('sort', 'usage_desc')); $q = RiskPool::query()->where('draw_id', $draw->id); if ($soldOutOnly) { $q->where('sold_out_status', 1); } match ($sort) { 'locked_desc' => $q->orderByDesc('locked_amount')->orderBy('normalized_number'), 'remaining_asc' => $q->orderBy('remaining_amount')->orderBy('normalized_number'), 'number_asc' => $q->orderBy('normalized_number'), default => $q->orderByRaw('(locked_amount * 1.0 / NULLIF(total_cap_amount, 0)) DESC') ->orderByDesc('locked_amount') ->orderBy('normalized_number'), }; /** @var LengthAwarePaginator $paginator */ $paginator = $q->paginate($perPage); return ApiResponse::success([ 'draw_id' => (int) $draw->id, 'draw_no' => $draw->draw_no, 'items' => collect($paginator->items())->map(fn (RiskPool $row) => $this->row($row))->all(), 'meta' => [ 'current_page' => $paginator->currentPage(), 'per_page' => $paginator->perPage(), 'total' => $paginator->total(), 'last_page' => $paginator->lastPage(), ], ]); } /** @return array */ private function row(RiskPool $pool): array { $cap = (int) $pool->total_cap_amount; $locked = (int) $pool->locked_amount; return [ 'normalized_number' => $pool->normalized_number, 'total_cap_amount' => $cap, 'locked_amount' => $locked, 'remaining_amount' => (int) $pool->remaining_amount, 'sold_out_status' => (int) $pool->sold_out_status, 'is_sold_out' => (int) $pool->sold_out_status === 1, 'usage_ratio' => $cap > 0 ? round($locked / $cap, 6) : null, 'version' => (int) $pool->version, ]; } }