import { db } from '../db' /** * Parse a full name string (Russian format: "Фамилия Имя [Отчество]") * into first_name, last_name, middle_name parts. */ function parseName(fullName: string): { firstName: string; lastName: string; middleName: string | null } { const parts = fullName.trim().split(/\s+/) if (parts.length === 1) { return { firstName: parts[0], lastName: '', middleName: null } } return { lastName: parts[0], firstName: parts[1], middleName: parts[2] ?? null, } } /** * Create or update a guest record based on booking data. * - Matches existing guest by email OR phone (same hotel) * - If found: updates name/phone/email if they were empty * - If not found: creates new guest record * Non-throwing: errors are swallowed so booking creation is never blocked. */ export async function upsertGuestFromBooking(params: { hotelId: string guestName: string guestEmail?: string | null guestPhone?: string | null }): Promise { try { const { hotelId, guestName, guestEmail, guestPhone } = params if (!guestName?.trim()) return // Build match conditions const conditions: string[] = [] const matchParams: unknown[] = [hotelId] if (guestEmail?.trim()) { matchParams.push(guestEmail.toLowerCase().trim()) conditions.push(`LOWER(email) = $${matchParams.length}`) } if (guestPhone?.trim()) { const cleanPhone = guestPhone.replace(/\D/g, '') if (cleanPhone.length >= 7) { matchParams.push(cleanPhone) conditions.push(`REGEXP_REPLACE(phone, '[^0-9]', '', 'g') = $${matchParams.length}`) } } if (conditions.length > 0) { // Check if guest already exists const { rows } = await db.query( `SELECT id, first_name, last_name, email, phone FROM guests WHERE hotel_id = $1 AND (${conditions.join(' OR ')}) ORDER BY updated_at DESC LIMIT 1`, matchParams, ) if (rows[0]) { // Guest exists — fill in any blank fields const updates: string[] = [] const upParams: unknown[] = [] const g = rows[0] if ((!g.email || g.email === '') && guestEmail?.trim()) { upParams.push(guestEmail.toLowerCase().trim()) updates.push(`email = $${upParams.length}`) } if ((!g.phone || g.phone === '') && guestPhone?.trim()) { upParams.push(guestPhone.trim()) updates.push(`phone = $${upParams.length}`) } if (updates.length > 0) { upParams.push(rows[0].id) await db.query( `UPDATE guests SET ${updates.join(', ')}, updated_at = NOW() WHERE id = $${upParams.length}`, upParams, ) } return } } // No existing guest found — create new const { firstName, lastName, middleName } = parseName(guestName) await db.query( `INSERT INTO guests (hotel_id, first_name, last_name, middle_name, email, phone, loyalty_tier) VALUES ($1, $2, $3, $4, $5, $6, 'bronze')`, [ hotelId, firstName, lastName, middleName, guestEmail?.toLowerCase().trim() ?? null, guestPhone?.trim() ?? null, ], ) } catch { // Non-critical — never block booking creation } }