using CMSMicroservice.Application.Common.Interfaces; using CMSMicroservice.Domain.Enums; using Microsoft.EntityFrameworkCore; using System.Globalization; namespace CMSMicroservice.Application.CommissionCQ.Queries.GetAvailableWeeks; public class GetAvailableWeeksQueryHandler : IRequestHandler { private readonly IApplicationDbContext _context; public GetAvailableWeeksQueryHandler(IApplicationDbContext context) { _context = context; } public async Task Handle( GetAvailableWeeksQuery request, CancellationToken cancellationToken) { var currentDate = DateTime.Now; var currentWeekNumber = GetWeekNumber(currentDate); // دریافت هفته‌های محاسبه شده از دیتابیس var calculatedPools = await _context.WeeklyCommissionPools .Where(p => p.IsCalculated) .OrderByDescending(p => p.WeekNumber) .Take(request.PastWeeksCount) .ToListAsync(cancellationToken); // دریافت لاگ‌های اجرا var executionLogs = await _context.WorkerExecutionLogs .Where(log => log.Status == WorkerExecutionStatus.Success || log.Status == WorkerExecutionStatus.Failed) .GroupBy(log => log.WeekNumber) .Select(g => new { WeekNumber = g.Key, LastLog = g.OrderByDescending(l => l.StartedAt).First() }) .ToDictionaryAsync(x => x.WeekNumber, x => x.LastLog, cancellationToken); var allWeeks = new List(); // هفته جاری var currentWeekInfo = CreateWeekInfo(currentDate, currentWeekNumber, calculatedPools, executionLogs); // هفته‌های گذشته (12 هفته) var pastWeeks = new List(); for (int i = 1; i <= request.PastWeeksCount; i++) { var pastDate = currentDate.AddDays(-7 * i); var weekNumber = GetWeekNumber(pastDate); pastWeeks.Add(CreateWeekInfo(pastDate, weekNumber, calculatedPools, executionLogs)); } // هفته‌های آینده (4 هفته) var futureWeeks = new List(); for (int i = 1; i <= request.FutureWeeksCount; i++) { var futureDate = currentDate.AddDays(7 * i); var weekNumber = GetWeekNumber(futureDate); futureWeeks.Add(CreateWeekInfo(futureDate, weekNumber, calculatedPools, executionLogs)); } // تفکیک به calculated و pending var calculatedWeeks = pastWeeks.Where(w => w.IsCalculated).ToList(); var pendingWeeks = pastWeeks.Where(w => !w.IsCalculated).ToList(); return new GetAvailableWeeksResponseDto { CurrentWeek = currentWeekInfo, CalculatedWeeks = calculatedWeeks, PendingWeeks = pendingWeeks, FutureWeeks = futureWeeks }; } private WeekInfoDto CreateWeekInfo( DateTime date, string weekNumber, List calculatedPools, Dictionary executionLogs) { var (startDate, endDate) = GetWeekRange(date); var pool = calculatedPools.FirstOrDefault(p => p.WeekNumber == weekNumber); var log = executionLogs.GetValueOrDefault(weekNumber); var isCalculated = pool != null && pool.IsCalculated; var displayText = $"{weekNumber} ({startDate:yyyy/MM/dd} - {endDate:yyyy/MM/dd})"; if (isCalculated) { displayText += " ✅ محاسبه شده"; } return new WeekInfoDto { WeekNumber = weekNumber, StartDate = startDate, EndDate = endDate, IsCalculated = isCalculated, CalculatedAt = pool?.CalculatedAt, LastExecutionStatus = log?.Status.ToString(), TotalPoolAmount = pool?.TotalPoolAmount, EligibleUsersCount = pool?.UserCommissionPayouts?.Count ?? 0, DisplayText = displayText }; } private static string GetWeekNumber(DateTime date) { var calendar = CultureInfo.InvariantCulture.Calendar; var weekOfYear = calendar.GetWeekOfYear( date, CalendarWeekRule.FirstFourDayWeek, DayOfWeek.Monday); return $"{date.Year}-W{weekOfYear:D2}"; } private static (DateTime startDate, DateTime endDate) GetWeekRange(DateTime date) { var dayOfWeek = (int)date.DayOfWeek; var daysToMonday = dayOfWeek == 0 ? 6 : dayOfWeek - 1; // اگر یکشنبه باشد، 6 روز عقب برو var startDate = date.Date.AddDays(-daysToMonday); var endDate = startDate.AddDays(6); return (startDate, endDate); } }