namespace CMSMicroservice.Application.NetworkMembershipCQ.Queries.GetUserNetworkPosition; public class GetUserNetworkPositionQueryHandler : IRequestHandler { private readonly IApplicationDbContext _context; public GetUserNetworkPositionQueryHandler(IApplicationDbContext context) { _context = context; } public async Task Handle(GetUserNetworkPositionQuery request, CancellationToken cancellationToken) { // واکشی اطلاعات اصلی کاربر var user = await _context.Users .AsNoTracking() .Where(x => x.Id == request.UserId) .Select(x => new { x.Id, x.Mobile, x.FirstName, x.LastName, x.Email, x.NationalCode, x.ReferralCode, x.IsMobileVerified, x.BirthDate, x.NetworkParentId, x.LegPosition, x.HasReceivedDayaCredit, x.DayaCreditReceivedAt, x.PackagePurchaseMethod, x.Created }) .FirstOrDefaultAsync(cancellationToken); if (user == null) { return null; } // اطلاعات والد string? parentMobile = null; string? parentFullName = null; if (user.NetworkParentId.HasValue) { var parent = await _context.Users .Where(x => x.Id == user.NetworkParentId) .Select(x => new { x.Mobile, x.FirstName, x.LastName }) .FirstOrDefaultAsync(cancellationToken); if (parent != null) { parentMobile = parent.Mobile; parentFullName = $"{parent.FirstName} {parent.LastName}".Trim(); } } // شمارش فرزندان مستقیم var directChildren = await _context.Users .Where(x => x.NetworkParentId == request.UserId) .Select(x => new { x.Id, x.LegPosition, x.FirstName, x.LastName, x.Mobile, x.Created }) .ToListAsync(cancellationToken); var leftChild = directChildren.FirstOrDefault(x => x.LegPosition == NetworkLeg.Left); var rightChild = directChildren.FirstOrDefault(x => x.LegPosition == NetworkLeg.Right); // محاسبه تعداد کل اعضای هر شاخه (با استفاده از CTE برای عملکرد بهتر) var leftLegCount = await GetLegMemberCountAsync(request.UserId, NetworkLeg.Left, cancellationToken); var rightLegCount = await GetLegMemberCountAsync(request.UserId, NetworkLeg.Right, cancellationToken); var totalNetworkSize = leftLegCount + rightLegCount; // محاسبه حداکثر عمق شبکه var maxDepth = await GetMaxNetworkDepthAsync(request.UserId, cancellationToken); // آمار اعضای فعال/غیرفعال (کسانی که پکیج خریده‌اند) var allDescendantIds = await GetAllDescendantIdsAsync(request.UserId, cancellationToken); var activeCount = await _context.Users .CountAsync(x => allDescendantIds.Contains(x.Id) && x.PackagePurchaseMethod != PackagePurchaseMethod.None, cancellationToken); var inactiveCount = allDescendantIds.Count - activeCount; // آمار کمیسیون‌های کاربر var commissionStats = await _context.UserCommissionPayouts .Where(x => x.UserId == request.UserId) .GroupBy(x => x.UserId) .Select(g => new { TotalBalances = g.Sum(x => x.BalancesEarned), TotalAmount = g.Sum(x => x.TotalAmount), PaidAmount = g.Where(x => x.Status == CommissionPayoutStatus.Paid).Sum(x => x.TotalAmount), PendingAmount = g.Where(x => x.Status == CommissionPayoutStatus.Pending).Sum(x => x.TotalAmount) }) .FirstOrDefaultAsync(cancellationToken); return new UserNetworkPositionDto { // اطلاعات اصلی UserId = user.Id, Mobile = user.Mobile, FirstName = user.FirstName, LastName = user.LastName, Email = user.Email, NationalCode = user.NationalCode, ReferralCode = user.ReferralCode, IsMobileVerified = user.IsMobileVerified, BirthDate = user.BirthDate, JoinedAt = user.Created, // اطلاعات شبکه NetworkParentId = user.NetworkParentId, ParentMobile = parentMobile, ParentFullName = parentFullName, LegPosition = user.LegPosition, IsInNetwork = user.NetworkParentId.HasValue, // آمار فرزندان مستقیم TotalChildren = directChildren.Count, LeftChildCount = leftChild != null ? 1 : 0, RightChildCount = rightChild != null ? 1 : 0, // اطلاعات فرزند چپ LeftChildId = leftChild?.Id, LeftChildFullName = leftChild != null ? $"{leftChild.FirstName} {leftChild.LastName}".Trim() : null, LeftChildMobile = leftChild?.Mobile, LeftChildJoinedAt = leftChild?.Created, // اطلاعات فرزند راست RightChildId = rightChild?.Id, RightChildFullName = rightChild != null ? $"{rightChild.FirstName} {rightChild.LastName}".Trim() : null, RightChildMobile = rightChild?.Mobile, RightChildJoinedAt = rightChild?.Created, // آمار کل شبکه TotalLeftLegMembers = leftLegCount, TotalRightLegMembers = rightLegCount, TotalNetworkSize = totalNetworkSize, MaxNetworkDepth = maxDepth, // اطلاعات پکیج و دایا HasReceivedDayaCredit = user.HasReceivedDayaCredit, DayaCreditReceivedAt = user.DayaCreditReceivedAt, PackagePurchaseMethod = user.PackagePurchaseMethod, HasPurchasedGoldenPackage = user.PackagePurchaseMethod != PackagePurchaseMethod.None, // آمار مالی TotalEarnedCommission = commissionStats?.TotalAmount ?? 0, TotalPaidCommission = commissionStats?.PaidAmount ?? 0, PendingCommission = commissionStats?.PendingAmount ?? 0, TotalBalancesEarned = commissionStats?.TotalBalances ?? 0, // آمار فعالیت ActiveMembersInNetwork = activeCount, InactiveMembersInNetwork = inactiveCount }; } /// /// محاسبه تعداد اعضای یک شاخه (چپ یا راست) به صورت بازگشتی /// private async Task GetLegMemberCountAsync(long userId, NetworkLeg leg, CancellationToken cancellationToken) { var directChild = await _context.Users .Where(x => x.NetworkParentId == userId && x.LegPosition == leg) .Select(x => x.Id) .FirstOrDefaultAsync(cancellationToken); if (directChild == 0) return 0; // تعداد کل زیرمجموعه این فرزند + خود فرزند var descendants = await GetAllDescendantIdsAsync(directChild, cancellationToken); return descendants.Count + 1; // +1 برای خود فرزند } /// /// محاسبه حداکثر عمق شبکه /// private async Task GetMaxNetworkDepthAsync(long userId, CancellationToken cancellationToken) { var maxDepth = 0; var currentLevelIds = new List { userId }; while (currentLevelIds.Any()) { var nextLevelIds = await _context.Users .Where(x => currentLevelIds.Contains(x.NetworkParentId ?? 0)) .Select(x => x.Id) .ToListAsync(cancellationToken); if (nextLevelIds.Any()) { maxDepth++; currentLevelIds = nextLevelIds; } else { break; } } return maxDepth; } /// /// دریافت تمام ID های زیرمجموعه یک کاربر /// private async Task> GetAllDescendantIdsAsync(long userId, CancellationToken cancellationToken) { var allDescendants = new List(); var currentLevelIds = new List { userId }; while (currentLevelIds.Any()) { var children = await _context.Users .Where(x => currentLevelIds.Contains(x.NetworkParentId ?? 0)) .Select(x => x.Id) .ToListAsync(cancellationToken); if (children.Any()) { allDescendants.AddRange(children); currentLevelIds = children; } else { break; } } return allDescendants; } }