using CMSMicroservice.Protobuf.Protos.NetworkMembership; namespace FrontOffice.BFF.Application.NetworkMembershipCQ.Queries.GetMyNetworkStatistics; public class GetMyNetworkStatisticsQueryHandler : IRequestHandler { private readonly IApplicationContractContext _context; private readonly ICurrentUserService _currentUserService; public GetMyNetworkStatisticsQueryHandler( IApplicationContractContext context, ICurrentUserService currentUserService) { _context = context; _currentUserService = currentUserService; } public async Task Handle(GetMyNetworkStatisticsQuery request, CancellationToken cancellationToken) { var userId = _currentUserService.UserId ?? throw new UnauthorizedAccessException("User not authenticated"); // Get user's own network info which contains personal stats AND subtree stats var userNetworkRequest = new GetUserNetworkRequest { UserId = userId }; var userNetwork = await _context.NetworkMemberships.GetUserNetworkAsync(userNetworkRequest, cancellationToken: cancellationToken); // Calculate percentages from user's subtree stats var totalSubtreeMembers = userNetwork.TotalLeftLegMembers + userNetwork.TotalRightLegMembers; var leftPercentage = totalSubtreeMembers > 0 ? (double)userNetwork.TotalLeftLegMembers / totalSubtreeMembers * 100 : 0; var rightPercentage = totalSubtreeMembers > 0 ? (double)userNetwork.TotalRightLegMembers / totalSubtreeMembers * 100 : 0; var weakerLeg = userNetwork.TotalLeftLegMembers < userNetwork.TotalRightLegMembers ? "Left" : "Right"; // Get tree to find last member and calculate depth var treeRequest = new GetNetworkTreeRequest { UserId = userId, MaxDepth = 20 // Get deep enough to find last member }; var treeResponse = await _context.NetworkMemberships.GetNetworkTreeAsync(treeRequest, cancellationToken: cancellationToken); // Find the last joined member in user's subtree var lastMember = treeResponse.Nodes .Where(n => n.UserId != userId && n.JoinedAt != null) .OrderByDescending(n => n.JoinedAt) .FirstOrDefault(); // Calculate max depth from tree nodes var maxDepth = treeResponse.Nodes.Count > 0 ? treeResponse.Nodes.Max(n => n.NetworkLevel) - userNetwork.NetworkLevel : 0; // Calculate active members in user's subtree var activeMembers = treeResponse.Nodes.Count(n => n.IsActive); return new GetMyNetworkStatisticsResponseDto { // User's subtree stats from GetUserNetwork TotalMembers = userNetwork.TotalNetworkSize, ActiveMembers = activeMembers, LeftLegCount = userNetwork.TotalLeftLegMembers, RightLegCount = userNetwork.TotalRightLegMembers, LeftPercentage = Math.Round(leftPercentage, 2), RightPercentage = Math.Round(rightPercentage, 2), AverageDepth = 0, // Not available from current API MaxDepth = Math.Max(maxDepth, userNetwork.MaxNetworkDepth), WeakerLeg = weakerLeg, // User's personal info MyNetworkLevel = userNetwork.NetworkLevel, MyNetworkLeg = userNetwork.NetworkLeg == 0 ? "Left" : "Right", MyReferralCode = userNetwork.ReferralCode, // Last member info from tree LastMember = lastMember != null ? new LastMemberDto { UserId = lastMember.UserId, FullName = lastMember.UserName ?? string.Empty, Position = lastMember.NetworkLeg == 0 ? "Left" : "Right", TotalChildren = 0 // Would need another call to get this } : null }; } }