using Microsoft.EntityFrameworkCore; using Stylist.Data.Dtos.Salon; using Stylist.Data.Models; using Stylist.Data.Models.Dtos.Schedule; using Stylist.Domain.Repositories.Interfaces; namespace Stylist.Domain.Repositories.Implementations { public class ScheduleRepository : IScheduleRepository { public ScheduleRepository(StylistContext context) { _context = context; } private readonly StylistContext _context; public async Task<IEnumerable<ScheduleAvailableSlotDto>> GetAllHairdresserAvailableSlotsByDate(int hairdresserId, DateTime date, int duration) { var schedule = await _context .Schedules .Include(s => s.Reservations) .Where(s => s.HairdresserId == hairdresserId) .Where(s => s.Starts.Date == date.Date && s.Ends.Date == date.Date) .FirstOrDefaultAsync(); if (schedule == null) { return []; } var availableSlots = new List<ScheduleAvailableSlotDto>(); var scheduleStart = TimeOnly.FromDateTime(schedule.Starts); var scheduleEnd = TimeOnly.FromDateTime(schedule.Ends); var freeSlotStart = scheduleStart; var freeSlotEnd = freeSlotStart.AddMinutes(duration); while (freeSlotEnd <= scheduleEnd) { var isAnyReservrationDuringSlot = schedule.Reservations.Any(r => isSlotReserved(r.Starts, r.Ends, freeSlotStart, freeSlotEnd)); if (!isAnyReservrationDuringSlot) availableSlots.Add(new ScheduleAvailableSlotDto { Starts = freeSlotStart, Ends = freeSlotEnd, }); freeSlotStart = freeSlotStart.AddMinutes(15); freeSlotEnd = freeSlotEnd.AddMinutes(15); } return availableSlots; } private static bool isSlotReserved(TimeOnly reservationStart, TimeOnly reservationEnd, TimeOnly startFreeSlot, TimeOnly endFreeSlot) { return reservationStart.IsBetween(startFreeSlot, endFreeSlot) || reservationEnd.IsBetween(startFreeSlot, endFreeSlot) && startFreeSlot != reservationEnd && endFreeSlot != reservationStart || (startFreeSlot.IsBetween(reservationStart, reservationEnd) || endFreeSlot.IsBetween(reservationStart, reservationEnd)); } } }