import { requireAuth } from "@/lib/jwt"; import { sql } from "@/lib/db"; import { SERVICES } from "@/constants/services"; import { boundingBox, haversine } from "@/lib/utils"; import { DRIVER_STALE_SECONDS } from "@/constants/dispatch"; // GET — how many drivers of each service are within reach of a point. // // The rider map filters by the selected service, so an empty map is ambiguous: // it means "nobody at all" and "nobody driving a moto, though three cars are a // street away" identically. That's the state riders were getting stuck in — // staring at an empty map with no way to know that switching service would // fill it. This answers the question the map can't. // // Query: ?lat=33.89&lng=35.50&radius=20000 // // Returns every known service, zeros included, so the client can render the // full picker without inventing missing keys. const DEFAULT_RADIUS_M = 20000; const MAX_RADIUS_M = 20000; export async function GET(req: Request) { const auth = requireAuth(req); if ("error" in auth) return auth.error; try { const url = new URL(req.url); const lat = Number(url.searchParams.get("lat")); const lng = Number(url.searchParams.get("lng")); if (Number.isNaN(lat) || Number.isNaN(lng)) { return Response.json( { error: "lat and lng query params are required numbers." }, { status: 400 }, ); } const requested = Number(url.searchParams.get("radius")); const radius = Number.isFinite(requested) && requested > 0 ? Math.min(requested, MAX_RADIUS_M) : DEFAULT_RADIUS_M; const box = boundingBox(lat, lng, radius); // Same visibility rules as /driver/nearby — vetted, online, fresh, real // account, positioned. A driver riders can't be matched to must not be // counted here either, or the hint sends them to an empty service. const rows = await sql<{ service: string; latitude: number; longitude: number; }>` SELECT service, latitude, longitude FROM drivers WHERE online = TRUE AND approval_status = 'approved' AND user_id IS NOT NULL AND last_seen > CURRENT_TIMESTAMP - make_interval(secs => ${DRIVER_STALE_SECONDS}) AND latitude IS NOT NULL AND longitude IS NOT NULL AND latitude BETWEEN ${box.minLat} AND ${box.maxLat} AND longitude BETWEEN ${box.minLng} AND ${box.maxLng} `; const counts: Record = {}; for (const service of SERVICES) counts[service.id] = 0; for (const row of rows) { if (haversine(lat, lng, row.latitude, row.longitude) > radius) continue; if (counts[row.service] === undefined) continue; counts[row.service] += 1; } return Response.json({ data: { radius, counts } }); } catch (error) { console.error("[DRIVER_AVAILABILITY]: ", error); return Response.json({ error: "Internal Server Error" }, { status: 500 }); } }