using Fitness_core_BE.Interfaces; using Fitness_core_BE.Models; using Microsoft.EntityFrameworkCore; namespace Fitness_core_BE.Repos { public class CustomerPlanRepository : ICustomerPlanRepository { // Client is central-bucket -- CustomerPlan.Client can't be a same-context Include once // central/tenant are physically separate (see TenantDbContext.OnModelCreating). Loaded // separately here and attached in memory, same convention as StaffRepository.User. private readonly TenantDbContext _context; private readonly CentralDbContext _central; public CustomerPlanRepository(TenantDbContext context, CentralDbContext central) { _context = context; _central = central; } private async Task AttachClientsAsync(IEnumerable plans) { var clientIds = plans.Select(p => p.FKClientId).Distinct().ToList(); if (clientIds.Count == 0) return; var clients = await _central.Client .AsNoTracking() .Where(c => clientIds.Contains(c.ClientId)) .ToDictionaryAsync(c => c.ClientId); foreach (var plan in plans) { if (clients.TryGetValue(plan.FKClientId, out var client)) plan.Client = client; } } public async Task> GetAllCustomerPlans(bool includeInactive = false, Guid? clientId = null) { var query = _context.CustomerPlans.AsQueryable(); if (clientId.HasValue) { query = query.Where(cp => cp.FKClientId == clientId.Value); } if (!includeInactive) { query = query.Where(cp => cp.IsActive); } var plans = await query .OrderBy(cp => cp.PlanName) .ToListAsync(); await AttachClientsAsync(plans); return plans; } public async Task GetCustomerPlanById(Guid customerPlanId) { var plan = await _context.CustomerPlans .FirstOrDefaultAsync(cp => cp.CustomerPlanId == customerPlanId); if (plan != null) await AttachClientsAsync(new[] { plan }); return plan; } public async Task CreateCustomerPlan(CustomerPlan customerPlan) { customerPlan.CustomerPlanId = Guid.NewGuid(); customerPlan.CreatedAt = DateTime.UtcNow; customerPlan.IsActive = true; _context.CustomerPlans.Add(customerPlan); return customerPlan; } public async Task UpdateCustomerPlan(CustomerPlan customerPlan) { var existingPlan = await _context.CustomerPlans.FindAsync(customerPlan.CustomerPlanId); if (existingPlan == null) { throw new Exception("Customer Plan not found"); } // The service merges provided keys onto the loaded entity and validates // the combined configuration, so this is a direct full assignment. existingPlan.PlanName = customerPlan.PlanName; existingPlan.PlanDescription = customerPlan.PlanDescription; existingPlan.PlanPrice = customerPlan.PlanPrice; existingPlan.DurationInDays = customerPlan.DurationInDays; existingPlan.PlanScope = customerPlan.PlanScope; existingPlan.MemberLimit = customerPlan.MemberLimit; existingPlan.DurationMode = customerPlan.DurationMode; existingPlan.ValidFrom = customerPlan.ValidFrom; existingPlan.ValidTo = customerPlan.ValidTo; existingPlan.AllowSplitPayments = customerPlan.AllowSplitPayments; existingPlan.InstallmentCount = customerPlan.InstallmentCount; existingPlan.SessionsPerCycle = customerPlan.SessionsPerCycle; existingPlan.SessionRolloverPolicy = customerPlan.SessionRolloverPolicy; existingPlan.RolloverGraceDays = customerPlan.RolloverGraceDays; existingPlan.BillingTiming = customerPlan.BillingTiming; existingPlan.IsActive = customerPlan.IsActive; return existingPlan; } public async Task SetCustomerPlanActive(Guid customerPlanId, Guid clientId, bool isActive) { var plan = await _context.CustomerPlans .FirstOrDefaultAsync(cp => cp.CustomerPlanId == customerPlanId && cp.FKClientId == clientId); if (plan == null) return null; plan.IsActive = isActive; await AttachClientsAsync(new[] { plan }); return plan; } public async Task DeleteCustomerPlan(Guid customerPlanId, bool softDelete = true) { var customerPlan = await _context.CustomerPlans.FindAsync(customerPlanId); if (customerPlan == null) { return false; } if (softDelete) { // Soft delete: just mark as inactive customerPlan.IsActive = false; } else { // Hard delete: remove from database _context.CustomerPlans.Remove(customerPlan); } return true; } } }