import { NextRequest, NextResponse } from "next/server"; import { getPublicUser, prisma } from "@repo/db"; import { getServerSession } from "../auth/[...nextauth]/auth"; // GET /api/booking - Get all bookings for the timeline export const GET = async (req: NextRequest) => { try { const session = await getServerSession(); if (!session?.user) { return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); } const { searchParams } = req.nextUrl; const filter = JSON.parse(searchParams.get("filter") || "{}"); const bookings = await prisma.booking.findMany({ where: filter, include: { User: true, Station: { select: { id: true, bosCallsign: true, bosCallsignShort: true, }, }, }, orderBy: { startTime: "asc", }, }); return NextResponse.json( bookings.map((b) => ({ ...b, User: b.User ? getPublicUser(b.User) : null, })), ); } catch (error) { console.error("Error fetching bookings:", error); return NextResponse.json({ error: "Internal server error" }, { status: 500 }); } }; // POST /api/booking - Create a new booking export const POST = async (req: NextRequest) => { try { const session = await getServerSession(); if (!session?.user) { return NextResponse.json({ error: "Not authenticated" }, { status: 401 }); } const body = await req.json(); const { type, stationId, startTime, endTime } = body; // Convert stationId to integer if provided const parsedStationId = stationId ? parseInt(stationId, 10) : null; // Validate required fields if (!type || !startTime || !endTime) { return NextResponse.json({ error: "Missing required fields" }, { status: 400 }); } // Validate permissions for LST bookings const lstTypes = ["LST_01", "LST_02", "LST_03", "LST_04"]; if (lstTypes.includes(type)) { if (!session.user.permissions.includes("DISPO")) { return NextResponse.json( { error: "Insufficient permissions for LST booking" }, { status: 403 }, ); } } // Validate station requirement for STATION type if (type === "STATION" && !parsedStationId) { return NextResponse.json( { error: "Station ID required for station booking" }, { status: 400 }, ); } // Validate that stationId is a valid integer when provided if (stationId && (isNaN(parsedStationId!) || parsedStationId! <= 0)) { return NextResponse.json({ error: "Invalid station ID" }, { status: 400 }); } // Check for conflicts const conflictWhere: Record = { type, OR: [ { startTime: { lt: new Date(endTime), }, endTime: { gt: new Date(startTime), }, }, ], }; if (type === "STATION" && parsedStationId) { conflictWhere.stationId = parsedStationId; } const existingBooking = await prisma.booking.findFirst({ where: conflictWhere, }); if (existingBooking) { const resourceName = type === "STATION" ? `Station` : type; return NextResponse.json( { error: `Konflikt erkannt: ${resourceName} ist bereits für diesen Zeitraum gebucht.` }, { status: 409 }, ); } // Create the booking const booking = await prisma.booking.create({ data: { userId: session.user.id, type, stationId: type === "STATION" ? parsedStationId : null, startTime: new Date(startTime), endTime: new Date(endTime), }, include: { User: { select: { id: true, firstname: true, lastname: true, }, }, Station: { select: { id: true, bosCallsign: true, bosCallsignShort: true, }, }, }, }); return NextResponse.json(booking, { status: 201 }); } catch (error) { console.error("Error creating booking:", error); return NextResponse.json({ error: "Internal server error" }, { status: 500 }); } };