namespace CMSMicroservice.Application.ClubMembershipCQ.Queries.GetClubStatistics; public class GetClubStatisticsQueryHandler : IRequestHandler { private readonly IApplicationDbContext _context; public GetClubStatisticsQueryHandler(IApplicationDbContext context) { _context = context; } public async Task Handle(GetClubStatisticsQuery request, CancellationToken cancellationToken) { var now = DateTime.UtcNow; // Basic statistics var totalMembers = await _context.ClubMemberships.CountAsync(cancellationToken); var activeMembers = await _context.ClubMemberships .Where(x => x.IsActive) .CountAsync(cancellationToken); var inactiveMembers = totalMembers - activeMembers; var expiredMembers = 0; // Since there's no expiration tracking in the model double activePercentage = totalMembers > 0 ? (activeMembers / (double)totalMembers) * 100 : 0; // Package distribution - ClubMembership doesn't have PackageId // We'll return empty list for now or create mock data var packageDistribution = new List(); // Monthly trend (last 6 months) var sixMonthsAgo = now.AddMonths(-6); var activations = await _context.ClubMemberships .Where(x => x.ActivatedAt >= sixMonthsAgo && x.ActivatedAt != null) .GroupBy(x => new { x.ActivatedAt!.Value.Year, x.ActivatedAt.Value.Month }) .Select(g => new { g.Key.Year, g.Key.Month, Count = g.Count() }) .ToListAsync(cancellationToken); var monthlyTrend = new List(); for (int i = 5; i >= 0; i--) { var targetDate = now.AddMonths(-i); var year = targetDate.Year; var month = targetDate.Month; var activationCount = activations.FirstOrDefault(x => x.Year == year && x.Month == month)?.Count ?? 0; monthlyTrend.Add(new MonthlyMembershipTrendModel { Month = $"{year}-{month:D2}", Activations = activationCount, Expirations = 0, // No expiration tracking NetChange = activationCount }); } // Total revenue - sum of initial contributions var totalRevenue = await _context.ClubMemberships .SumAsync(x => x.InitialContribution, cancellationToken); // Average membership duration - calculate from ActivatedAt to now var activeMemberships = await _context.ClubMemberships .Where(x => x.IsActive && x.ActivatedAt != null) .Select(x => x.ActivatedAt!.Value) .ToListAsync(cancellationToken); double averageDuration = 0; if (activeMemberships.Any()) { var durations = activeMemberships .Select(activatedAt => (now - activatedAt).TotalDays) .ToList(); averageDuration = durations.Average(); } // Expiring soon count - not applicable since no expiration tracking int expiringSoonCount = 0; return new GetClubStatisticsResponseDto { TotalMembers = totalMembers, ActiveMembers = activeMembers, InactiveMembers = inactiveMembers, ExpiredMembers = expiredMembers, ActivePercentage = activePercentage, PackageDistribution = packageDistribution, MonthlyTrend = monthlyTrend, TotalRevenue = totalRevenue, AverageMembershipDurationDays = averageDuration, ExpiringSoonCount = expiringSoonCount }; } }