package com.android.trisolarisserver.controller import com.android.trisolarisserver.controller.dto.BookingDetailResponse import com.android.trisolarisserver.db.repo.BookingRepo import com.android.trisolarisserver.repo.GuestVehicleRepo import com.android.trisolarisserver.repo.PaymentRepo import com.android.trisolarisserver.repo.RoomStayRepo import org.springframework.http.HttpStatus import org.springframework.stereotype.Component import org.springframework.web.server.ResponseStatusException import java.util.UUID @Component class BookingSnapshotBuilder( private val bookingRepo: BookingRepo, private val roomStayRepo: RoomStayRepo, private val paymentRepo: PaymentRepo, private val guestVehicleRepo: GuestVehicleRepo ) { fun build(propertyId: UUID, bookingId: UUID): BookingDetailResponse { val booking = bookingRepo.findById(bookingId).orElseThrow { ResponseStatusException(HttpStatus.NOT_FOUND, "Booking not found") } if (booking.property.id != propertyId) { throw ResponseStatusException(HttpStatus.NOT_FOUND, "Booking not found for property") } val stays = roomStayRepo.findByBookingId(bookingId) val activeRooms = stays.filter { it.toAt == null } val roomsToShow = activeRooms.ifEmpty { stays } val roomNumbers = roomsToShow.map { it.room.roomNumber } .distinct() .sorted() val guest = booking.primaryGuest val vehicleNumbers = if (guest?.id != null) { guestVehicleRepo.findByGuestIdIn(listOf(guest.id!!)) .map { it.vehicleNumber } .distinct() .sorted() } else { emptyList() } val signatureUrl = guest?.signaturePath?.let { "/properties/$propertyId/guests/${guest.id}/signature/file" } val totalNightlyRate = roomsToShow.sumOf { it.nightlyRate ?: 0L } val expectedPay = computeExpectedPayTotal(stays, booking.expectedCheckoutAt, booking.property.timezone) val accruedPay = computeExpectedPay(stays, booking.property.timezone) val amountCollected = paymentRepo.sumAmountByBookingId(bookingId) val pending = accruedPay - amountCollected return BookingDetailResponse( id = booking.id!!, status = booking.status.name, guestId = guest?.id, guestName = guest?.name, guestPhone = guest?.phoneE164, guestNationality = guest?.nationality, guestAddressText = guest?.addressText, guestSignatureUrl = signatureUrl, vehicleNumbers = vehicleNumbers, roomNumbers = roomNumbers, source = booking.source, fromCity = booking.fromCity, toCity = booking.toCity, memberRelation = booking.memberRelation?.name, transportMode = booking.transportMode?.name, checkInAt = booking.checkinAt?.toString(), checkOutAt = booking.checkoutAt?.toString(), expectedCheckInAt = booking.expectedCheckinAt?.toString(), expectedCheckOutAt = booking.expectedCheckoutAt?.toString(), adultCount = booking.adultCount, childCount = booking.childCount, maleCount = booking.maleCount, femaleCount = booking.femaleCount, totalGuestCount = booking.totalGuestCount, expectedGuestCount = booking.expectedGuestCount, notes = booking.notes, registeredByName = booking.createdBy?.name, registeredByPhone = booking.createdBy?.phoneE164, totalNightlyRate = totalNightlyRate, expectedPay = expectedPay, amountCollected = amountCollected, pending = pending ) } }