import Series from "../../../../models/series.js"; import Event from "../../../../models/event.js"; import Member from "../../../../models/member.js"; import { validateSeriesTicketPurchase, calculateSeriesTicketPrice, reserveSeriesTicket, releaseSeriesTicket, completeSeriesTicketPurchase, registerForAllSeriesEvents, } from "../../../../utils/tickets.js"; import { sendSeriesPassConfirmation } from "../../../../utils/resend.js"; export default defineEventHandler(async (event) => { try { const seriesId = getRouterParam(event, "id"); const body = await readBody(event); const { name, email, paymentId } = body; // Validate input if (!name || !email) { throw createError({ statusCode: 400, statusMessage: "Name and email are required", }); } // Fetch series // Build query conditions based on whether seriesId looks like ObjectId or string const isObjectId = /^[0-9a-fA-F]{24}$/.test(seriesId); const seriesQuery = isObjectId ? { $or: [{ _id: seriesId }, { id: seriesId }, { slug: seriesId }] } : { $or: [{ id: seriesId }, { slug: seriesId }] }; const series = await Series.findOne(seriesQuery); if (!series) { throw createError({ statusCode: 404, statusMessage: "Series not found", }); } // Check membership let member = null; member = await Member.findOne({ email: email.toLowerCase() }); // Validate purchase const validation = validateSeriesTicketPurchase(series, { email, name, member, }); if (!validation.valid) { throw createError({ statusCode: 400, statusMessage: validation.reason, }); } const { ticketInfo } = validation; // For paid tickets, require payment ID if (!ticketInfo.isFree && !paymentId) { throw createError({ statusCode: 400, statusMessage: "Payment is required for this series pass", }); } // Create series registration const registration = { memberId: member?._id, name, email: email.toLowerCase(), membershipLevel: member?.circle || "non-member", isMember: !!member, ticketType: ticketInfo.ticketType, ticketPrice: ticketInfo.price, paymentStatus: ticketInfo.isFree ? "not_required" : "completed", paymentId: paymentId || null, amountPaid: ticketInfo.price, registeredAt: new Date(), eventRegistrations: [], }; series.registrations.push(registration); await completeSeriesTicketPurchase(series, ticketInfo.ticketType); // Get the newly created registration const newRegistration = series.registrations[series.registrations.length - 1]; // Fetch all events in this series const seriesEvents = await Event.find({ "series.id": series.id, isCancelled: false, }).sort({ "series.position": 1, startDate: 1 }); // Register user for all events const eventRegistrations = await registerForAllSeriesEvents( series, seriesEvents, newRegistration, ); // Send confirmation email try { await sendSeriesPassConfirmation({ to: email, name, series: { title: series.title, description: series.description, type: series.type, }, ticket: { type: ticketInfo.ticketType, price: ticketInfo.price, currency: ticketInfo.currency, isFree: ticketInfo.isFree, }, events: seriesEvents.map((e) => ({ title: e.title, startDate: e.startDate, endDate: e.endDate, location: e.location, })), paymentId, }); } catch (emailError) { console.error( "Failed to send series pass confirmation email:", emailError, ); // Don't fail the registration if email fails } return { success: true, message: "Series pass purchased successfully", registration: { id: newRegistration._id, ticketType: newRegistration.ticketType, amountPaid: newRegistration.amountPaid, eventsRegistered: eventRegistrations.filter((r) => r.success).length, totalEvents: seriesEvents.length, }, events: eventRegistrations.map((r) => ({ eventId: r.eventId, success: r.success, reason: r.reason, })), }; } catch (error) { console.error("Error purchasing series pass:", error); throw createError({ statusCode: error.statusCode || 500, statusMessage: error.statusMessage || "Failed to purchase series pass", }); } });