import { NextRequest, NextResponse } from "next/server"; import { 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 } = new URL(req.url); const startDate = searchParams.get("startDate"); const endDate = searchParams.get("endDate"); const whereClause: Record = {}; // Filter by date range if provided if (startDate && endDate) { whereClause.OR = [ { startTime: { gte: new Date(startDate), lte: new Date(endDate), }, }, { endTime: { gte: new Date(startDate), lte: new Date(endDate), }, }, { AND: [ { startTime: { lte: new Date(startDate) } }, { endTime: { gte: new Date(endDate) } }, ], }, ]; } const bookings = await prisma.booking.findMany({ where: whereClause, include: { user: { select: { id: true, firstname: true, lastname: true, }, }, station: { select: { id: true, bosCallsign: true, bosCallsignShort: true, }, }, }, orderBy: { startTime: "asc", }, }); return NextResponse.json({ bookings }); } 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 }); } };