import { inArray, sum } from "drizzle-orm"; import { apiJson } from "@/lib/api"; import { db, RadioListenerPoints, User } from "@/lib/db"; // Radio listener-points leaderboard: the top 20 users by total points, summed // across radio_listener_points and joined to users for username/look. Public // (no auth) — mirrors the AtomCMS radio leaderboard widget. export const dynamic = "force-dynamic"; export async function GET(_req: Request) { try { // Sum points per user. Sort/slice in JS so we stay adapter-agnostic about // aggregate ordering, then resolve the top 20 to usernames/looks. const grouped = await db .select({ userId: RadioListenerPoints.userId, points: sum(RadioListenerPoints.points), }) .from(RadioListenerPoints) .groupBy(RadioListenerPoints.userId); const ranked = grouped .map((g) => ({ userId: Number(g.userId), points: Number(g.points ?? 0), })) .sort((a, b) => b.points - a.points) .slice(0, 20); if (ranked.length === 0) { return apiJson({ data: [] }); } const userIds = ranked.map((r) => r.userId); const users = await db .select({ id: User.id, username: User.username, look: User.look }) .from(User) .where(inArray(User.id, userIds)); const userById = new Map(users.map((u) => [u.id, u])); const data = ranked.map((r) => { const u = userById.get(r.userId); return { username: u?.username ?? null, look: u?.look ?? null, points: r.points, }; }); return apiJson({ data }); } catch { // DB unavailable — serve an empty leaderboard rather than a 500. return apiJson({ data: [] }, { status: 200 }); } }