import { fail, handleOptions, json } from "../_shared/http.ts"; import { requireUser } from "../_shared/supabase.ts"; const PAGE_SIZE = 20; Deno.serve(async (req) => { const preflight = handleOptions(req); if (preflight) return preflight; if (req.method !== "POST") return fail("Method not allowed", 405); const { client, user, error: userError } = await requireUser(req); if (!user) return fail(userError ?? "Unauthorized", 401); let body: { channel_id?: string; schedule_id?: string; stop_name?: string; offset?: number; limit?: number; }; try { body = await req.json(); } catch { return fail("Invalid JSON body"); } const channelId = (body.channel_id ?? "").trim(); const scheduleId = (body.schedule_id ?? "").trim(); const stopName = (body.stop_name ?? "").trim(); const offset = Math.max(0, typeof body.offset === "number" ? body.offset : 0); const limit = Math.min(100, Math.max(1, typeof body.limit === "number" ? body.limit : PAGE_SIZE)); if (!channelId) return fail("channel_id is required"); if (!scheduleId) return fail("schedule_id is required"); if (!stopName) return fail("stop_name is required"); const { data: schedule, error: scheduleError } = await client .from("operations_schedules") .select("id, channel_id") .eq("id", scheduleId) .eq("channel_id", channelId) .maybeSingle(); if (scheduleError) return fail(scheduleError.message, 400); if (!schedule) return fail("forbidden", 403); const { data: tripRows, error: tripError } = await client .from("operations_trips") .select("id, trip_number, duty_number, bus_work_number, direction") .eq("schedule_id", scheduleId); if (tripError) return fail(tripError.message, 500); const trips = (tripRows ?? []) as { id: string; trip_number: string; duty_number: string; bus_work_number: string; direction: string; }[]; if (trips.length === 0) return json({ schedule: [], has_more: false }); const tripIds = trips.map((t) => t.id); const tripById = Object.fromEntries(trips.map((t) => [t.id, t])); const { data: stopRows, error: stopError } = await client .from("operations_trip_stops") .select("trip_id, scheduled_time") .in("trip_id", tripIds) .eq("stop_name", stopName); if (stopError) return fail(stopError.message, 500); const rows = (stopRows ?? []) as { trip_id: string; scheduled_time: string | null }[]; const result = rows .map((row) => { const trip = tripById[row.trip_id]; if (!trip) return null; return { trip, scheduled_time: row.scheduled_time ?? null }; }) .filter(Boolean) as { trip: typeof trips[0]; scheduled_time: string | null }[]; result.sort((a, b) => { const aNum = parseInt(a.trip.trip_number, 10); const bNum = parseInt(b.trip.trip_number, 10); if (!isNaN(aNum) && !isNaN(bNum)) return aNum - bNum; return a.trip.trip_number.localeCompare(b.trip.trip_number); }); const page = result.slice(offset, offset + limit); const hasMore = offset + limit < result.length; return json({ schedule: page, has_more: hasMore }); });