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 year = date.Year; // پیدا کردن اولین شنبه سال var jan1 = new DateTime(year, 1, 1); var jan1DayOfWeek = (int)jan1.DayOfWeek; // 0=Sunday, 1=Monday, ..., 6=Saturday // محاسبه تعداد روزهایی که باید اضافه کنیم تا به اولین شنبه برسیم var daysToFirstSaturday = jan1DayOfWeek == 6 ? 0 : (6 - jan1DayOfWeek + 7) % 7; var firstSaturday = jan1.AddDays(daysToFirstSaturday); // پیدا کردن شنبه شروع هفته جاری var currentDayOfWeek = (int)date.DayOfWeek; // 0=Sun, 1=Mon, ..., 6=Sat var daysToCurrentSaturday = currentDayOfWeek == 6 ? 0 : (currentDayOfWeek + 1) % 7; var weekStartSaturday = date.Date.AddDays(-daysToCurrentSaturday); // محاسبه شماره هفته int weekNum; if (weekStartSaturday < firstSaturday) { weekNum = 1; // هفته اول سال } else { var daysSinceFirstSaturday = (weekStartSaturday - firstSaturday).Days; weekNum = (daysSinceFirstSaturday / 7) + 1; } return $"{year}-W{weekNum:D2}"; } private static (DateTime startDate, DateTime endDate) GetWeekRange(DateTime date) { var dayOfWeek = (int)date.DayOfWeek; // محاسبه تعداد روزهایی که باید عقب برویم تا به شنبه برسیم // شنبه = 6, یکشنبه = 0, دوشنبه = 1, ..., جمعه = 5 var daysToSaturday = dayOfWeek == 6 ? 0 : (dayOfWeek + 1) % 7; var startDate = date.Date.AddDays(-daysToSaturday); var endDate = startDate.AddDays(6).AddHours(23).AddMinutes(59).AddSeconds(59); return (startDate, endDate); } }