import type { BookingCapacitySettings, BookingMode, PublicBooking, TicketType } from '~~/shared/booking' import { formatBookingCurrency } from '~~/shared/booking' import { hasValidFullName, isValidPhoneNumber, normalizeFullName, normalizePhoneNumber } from '~~/shared/auth' import { assertBadRequest } from './http' export function parseCreateBookingInput(body: { customerName?: string customerPhone?: string bookingMode?: BookingMode | string | null quantity?: number ticketType?: TicketType personInChargeId?: string }) { const customerName = normalizeFullName(body.customerName || '') const customerPhone = normalizePhoneNumber(body.customerPhone || '') const bookingMode = typeof body.bookingMode === 'string' ? body.bookingMode.trim().toLowerCase() : body.bookingMode const ticketType = typeof body.ticketType === 'string' ? body.ticketType.trim().toLowerCase() : body.ticketType const quantity = Number(body.quantity) const personInChargeId = (body.personInChargeId || '').trim() assertBadRequest(hasValidFullName(customerName), 'Guest or organizer name must be at least 2 characters') assertBadRequest(isValidPhoneNumber(customerPhone), 'Phone number must include a country code, e.g. +60123456789') assertBadRequest(typeof bookingMode === 'string' && bookingMode.length > 0, 'Booking mode is required') assertBadRequest(Number.isInteger(quantity) && quantity >= 1, 'Quantity must be a whole number of at least 1') assertBadRequest(typeof ticketType === 'string' && ticketType.trim().length > 0, 'Ticket category is required') assertBadRequest(personInChargeId, 'Person in charge is required') return { customerName, customerPhone, bookingMode, quantity, ticketType, personInChargeId } } export function parseBookingRemarkInput(body: { remark?: string | null }) { const remark = typeof body.remark === 'string' ? body.remark.trim() : '' assertBadRequest(remark.length <= 1000, 'Remark must be 1,000 characters or fewer') return { remark: remark || null } } export function buildBookingMessage(booking: PublicBooking, confirmationUrl: string) { return [ `I'd like to book tickets for the ${booking.event.title}.`, '', `Name: ${booking.customerName}`, `Phone Number: ${booking.customerPhone}`, `Seats: ${booking.seatCount}`, `Ticket Category: ${booking.ticketLabel || booking.ticketType.toUpperCase()}`, `Total Price: ${formatBookingCurrency(booking.totalPrice)}`, '', 'PIC confirmation link:', confirmationUrl ].join('\n') } export function parseSeatShareInput(body: { shared?: boolean recipientName?: string | null recipientPhone?: string | null }) { const shared = body.shared const recipientName = normalizeFullName(body.recipientName || '') const recipientPhone = normalizePhoneNumber(body.recipientPhone || '') assertBadRequest(typeof shared === 'boolean', 'Shared flag is required') if (shared) { assertBadRequest(!recipientName || hasValidFullName(recipientName), 'Recipient name must be at least 2 characters') assertBadRequest(!recipientPhone || isValidPhoneNumber(recipientPhone), 'Recipient phone number must include a country code, e.g. +60123456789') } return { shared, recipientName: recipientName || null, recipientPhone: recipientPhone || null } } export function parseBookingCapacityInput(body: { totalSeats?: number | string | null }): Pick { const totalSeats = parseOptionalInteger(body.totalSeats) assertBadRequest(totalSeats === null || totalSeats >= 0, 'Total seats must be 0 or greater') return { totalSeats } } function parseOptionalInteger(value: number | string | null | undefined) { if (value === null || value === undefined || value === '') { return null } const parsed = typeof value === 'number' ? value : Number.parseInt(String(value), 10) assertBadRequest(Number.isInteger(parsed), 'Capacity values must be whole numbers') return parsed }