using Fitness_core_BE.Interfaces; using Fitness_core_BE.Models; using Microsoft.EntityFrameworkCore; namespace Fitness_core_BE.Repos { public class BookingRepository : IBookingRepository { private readonly TenantDbContext _context; public BookingRepository(TenantDbContext context) { _context = context; } public async Task CreateBooking(Booking booking) { booking.BookingId = Guid.NewGuid(); booking.CreatedAt = DateTime.UtcNow; _context.Bookings.Add(booking); return booking; } public Task GetBookingById(Guid bookingId) => _context.Bookings .Include(b => b.FacilitySession) .Include(b => b.Facility) .Include(b => b.RfidTag) .FirstOrDefaultAsync(b => b.BookingId == bookingId); public Task GetActiveBookingByOtp(string otpCode) => _context.Bookings .Include(b => b.FacilitySession) .Include(b => b.Facility) .Include(b => b.RfidTag) .FirstOrDefaultAsync(b => b.OtpCode == otpCode && b.Status == "Confirmed"); public Task> GetBookingsForSession(Guid facilitySessionId) => _context.Bookings .Include(b => b.Facility) .Include(b => b.RfidTag) .Where(b => b.FKFacilitySessionId == facilitySessionId) .OrderBy(b => b.BookedAt) .ToListAsync(); public Task> GetBookingsForCustomer(Guid customerId) => _context.Bookings .Include(b => b.FacilitySession) .Include(b => b.Facility) .Include(b => b.RfidTag) .Where(b => b.FKCustomerId == customerId) .OrderByDescending(b => b.BookedAt) .ToListAsync(); public Task CustomerHasActiveBookingForSession(Guid facilitySessionId, Guid customerId) => _context.Bookings.AnyAsync(b => b.FKFacilitySessionId == facilitySessionId && b.FKCustomerId == customerId && b.Status != "Cancelled"); public async Task> GetBookings(Guid clientId, Guid? facilityId, Guid? facilitySessionId, DateTime? fromUtc, DateTime? toUtc, string? status) { var query = _context.Bookings .Include(b => b.FacilitySession) .Include(b => b.Facility) .Include(b => b.RfidTag) .Where(b => b.FKClientId == clientId); if (facilityId.HasValue) query = query.Where(b => b.FKFacilityId == facilityId.Value); if (facilitySessionId.HasValue) query = query.Where(b => b.FKFacilitySessionId == facilitySessionId.Value); if (fromUtc.HasValue) query = query.Where(b => b.EndTime >= fromUtc.Value); if (toUtc.HasValue) query = query.Where(b => b.StartTime <= toUtc.Value); if (!string.IsNullOrEmpty(status)) query = query.Where(b => b.Status == status); return await query.OrderByDescending(b => b.StartTime).ToListAsync(); } public Task MarkOverdueConfirmedAsNoShowAsync(Guid clientId, DateTime now) => _context.Bookings .Where(b => b.FKClientId == clientId && b.Status == "Confirmed" && b.EndTime < now) .ExecuteUpdateAsync(s => s.SetProperty(b => b.Status, "NoShow")); public Task> GetOverdueCheckedInBookingsAsync(Guid clientId, DateTime now) => _context.Bookings .Include(b => b.RfidTag) .Where(b => b.FKClientId == clientId && b.Status == "CheckedIn" && b.EndTime < now) .ToListAsync(); public async Task TryClaimRfidTagAsync(Guid tagId, DateTime now) { var rows = await _context.RfidTags .Where(t => t.RfidTagId == tagId && t.Status == "Available") .ExecuteUpdateAsync(s => s .SetProperty(t => t.Status, "InUse") .SetProperty(t => t.UpdatedAt, now)); return rows > 0; } } }