import { NextResponse } from 'next/server'; import { prisma } from '@/lib/db'; import { getSessionUser } from '@/lib/auth'; export async function POST(request: Request) { try { const body = await request.json(); const { scheduleId, passengerName, passengerEmail, passengerPhone, seats, // Array of strings, e.g. ["1", "2"] or ["1A", "1B"] } = body; if (!scheduleId || !passengerName || !passengerEmail || !passengerPhone || !seats || !Array.isArray(seats) || seats.length === 0) { return NextResponse.json( { error: 'Missing required booking details or seat selections' }, { status: 400 } ); } // Fetch schedule to get the price const schedule = await prisma.schedule.findUnique({ where: { id: Number(scheduleId) }, }); if (!schedule) { return NextResponse.json({ error: 'Schedule not found' }, { status: 404 }); } // Check optional user session link const userSession = await getSessionUser(); const userId = userSession ? userSession.userId : null; // Calculate total price const unitPrice = Number(schedule.price); const totalPrice = unitPrice * seats.length; // Generate unique booking code const bookingCode = 'TRV-' + Math.random().toString(36).substring(2, 8).toUpperCase(); // Perform database transaction to ensure atomic operations (no double seat bookings) const booking = await prisma.$transaction(async (tx) => { // 1. Check if any selected seat is already occupied for this schedule const occupied = await tx.bookingSeat.findMany({ where: { scheduleId: Number(scheduleId), seatNumber: { in: seats }, booking: { status: { in: ['PENDING', 'PAID'] }, }, }, }); if (occupied.length > 0) { throw new Error('One or more selected seats have already been booked. Please choose other seats.'); } // 2. Create the booking record const newBooking = await tx.booking.create({ data: { bookingCode, scheduleId: Number(scheduleId), userId, passengerName, passengerEmail, passengerPhone, totalPrice, status: 'PENDING', }, }); // 3. Create the booking seat records const seatRecords = seats.map((seat: string) => ({ bookingId: newBooking.id, scheduleId: Number(scheduleId), seatNumber: seat, })); await tx.bookingSeat.createMany({ data: seatRecords, }); return newBooking; }); return NextResponse.json({ success: true, bookingCode: booking.bookingCode, bookingId: booking.id }); } catch (error: any) { console.error('Create booking transaction error:', error); return NextResponse.json( { error: error.message || 'Failed to process booking. Please try again.' }, { status: 400 } ); } }