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 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; } public async Task CreateBookingInvoice(BookingInvoice invoice) { invoice.BookingInvoiceId = Guid.NewGuid(); invoice.IssuedAt = DateTime.UtcNow; _context.BookingInvoices.Add(invoice); return invoice; } public Task> GetBookingInvoices(Guid clientId, DateTime? fromUtc, DateTime? toUtc) { var query = _context.BookingInvoices.Where(i => i.FKClientId == clientId); if (fromUtc.HasValue) query = query.Where(i => i.IssuedAt >= fromUtc.Value); if (toUtc.HasValue) query = query.Where(i => i.IssuedAt <= toUtc.Value); return query.OrderByDescending(i => i.IssuedAt).ToListAsync(); } public Task GetBookingInvoiceById(Guid bookingInvoiceId) => _context.BookingInvoices.FirstOrDefaultAsync(i => i.BookingInvoiceId == bookingInvoiceId); public async Task<(int bookingsToday, decimal revenueToday, int checkedInNow, int upcomingConfirmed, decimal outstandingUnpaid)> GetDashboardSummaryAsync(Guid clientId, DateTime now) { var todayStart = now.Date; var todayEnd = todayStart.AddDays(1); var bookingsToday = await _context.Bookings .CountAsync(b => b.FKClientId == clientId && b.StartTime >= todayStart && b.StartTime < todayEnd); var revenueToday = await _context.Bookings .Where(b => b.FKClientId == clientId && b.PaidAt >= todayStart && b.PaidAt < todayEnd) .SumAsync(b => (decimal?)b.AmountCharged) ?? 0m; var checkedInNow = await _context.Bookings .CountAsync(b => b.FKClientId == clientId && b.Status == "CheckedIn"); var upcomingConfirmed = await _context.Bookings .CountAsync(b => b.FKClientId == clientId && b.Status == "Confirmed" && b.StartTime > now); var outstandingUnpaid = await _context.Bookings .Where(b => b.FKClientId == clientId && b.PaymentStatus == "Unpaid") .SumAsync(b => (decimal?)b.AmountCharged) ?? 0m; return (bookingsToday, revenueToday, checkedInNow, upcomingConfirmed, outstandingUnpaid); } } }