import { type NextRequest, NextResponse } from 'next/server'; import { withAuth } from '@/lib/apiHelpers'; import pool from '@/lib/db'; export const GET = withAuth(async (req: NextRequest) => { const p = req.nextUrl.searchParams; const combinator = p.get('combinator'); const fromVal = p.get('from'); const toVal = p.get('to'); const from = fromVal ? new Date(fromVal) : new Date(Date.now() - 86_400_000); const to = toVal ? new Date(toVal) : new Date(); const conditions = ['real_time BETWEEN $1 AND $2']; const values: unknown[] = [from, to]; if (combinator) { conditions.push('combinator = $3'); values.push(combinator); } const result = await pool.query<{ real_time: Date; game_tick: string; combinator: string; }>( `SELECT real_time, game_tick, combinator FROM tick_timing WHERE ${conditions.join(' AND ')} ORDER BY real_time ASC`, values, ); const rows = result.rows; if (rows.length < 2) return NextResponse.json([]); const byCombi = new Map(); for (const row of rows) { const arr = byCombi.get(row.combinator) ?? []; arr.push(row); byCombi.set(row.combinator, arr); } const points: { real_time: string; game_tick: number; combinator: string; ups: number }[] = []; for (const [combi, combiRows] of byCombi) { for (let i = 1; i < combiRows.length; i++) { const prev = combiRows[i - 1]; const curr = combiRows[i]; const deltaRealMs = curr.real_time.getTime() - prev.real_time.getTime(); const deltaTicks = parseInt(curr.game_tick, 10) - parseInt(prev.game_tick, 10); // Skip session gaps and bad data if (deltaRealMs > 30 * 60 * 1000 || deltaRealMs <= 0 || deltaTicks <= 0) continue; points.push({ real_time: curr.real_time.toISOString(), game_tick: parseInt(curr.game_tick, 10), combinator: combi, ups: Math.round((deltaTicks / deltaRealMs) * 1000 * 10) / 10, }); } } return NextResponse.json(points); });