using CMSMicroservice.Protobuf.Protos.NetworkMembership; using CMSMicroservice.WebApi.Common.Services; using CMSMicroservice.Application.NetworkMembershipCQ.Commands.JoinNetwork; using CMSMicroservice.Application.NetworkMembershipCQ.Commands.MoveInNetwork; using CMSMicroservice.Application.NetworkMembershipCQ.Commands.RemoveFromNetwork; using CMSMicroservice.Application.NetworkMembershipCQ.Queries.GetUserNetworkPosition; using CMSMicroservice.Application.NetworkMembershipCQ.Queries.GetNetworkTree; using CMSMicroservice.Application.NetworkMembershipCQ.Queries.GetNetworkMembershipHistory; using CMSMicroservice.Application.NetworkMembershipCQ.Queries.GetNetworkStatistics; using CMSMicroservice.Application.NetworkMembershipCQ.Queries.GetMyNetworkTree; using CMSMicroservice.Application.Common.Interfaces; using Mapster; using CMSMicroservice.Domain.Enums; namespace CMSMicroservice.WebApi.Services; public class NetworkMembershipService : NetworkMembershipContract.NetworkMembershipContractBase { private readonly IDispatchRequestToCQRS _dispatchRequestToCQRS; private readonly ISender _sender; private readonly ICurrentUserService _currentUserService; public NetworkMembershipService( IDispatchRequestToCQRS dispatchRequestToCQRS, ISender sender, ICurrentUserService currentUserService) { _dispatchRequestToCQRS = dispatchRequestToCQRS; _sender = sender; _currentUserService = currentUserService; } public override async Task JoinNetwork(JoinNetworkRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle(request, context); } public override async Task ChangeNetworkParent(ChangeNetworkParentRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle(request, context); } public override async Task RemoveFromNetwork(RemoveFromNetworkRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle(request, context); } public override async Task GetUserNetwork(GetUserNetworkRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle(request, context); } public override async Task GetNetworkTree(GetNetworkTreeRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle(request, context); } public override async Task GetNetworkMembershipHistory(GetNetworkMembershipHistoryRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle(request, context); } public override async Task GetNetworkStatistics(GetNetworkStatisticsRequest request, ServerCallContext context) { return await _dispatchRequestToCQRS.Handle(request, context); } // ============= Customer-specific Methods ============= public override async Task GetMyNetworkTree(GetMyNetworkTreeRequest request, ServerCallContext context) { // Use Customer-specific Query that gets UserId from ICurrentUserService var query = new GetMyNetworkTreeQuery { MaxDepth = request.MaxDepth > 0 ? request.MaxDepth : 3 }; var tree = await _sender.Send(query, context.CancellationToken); if (tree == null) { return new GetMyNetworkTreeResponse { RootNode = null, TotalMembers = 0, CurrentDepth = 0 }; } // Convert NetworkTreeDto to NetworkTreeNodeModel var rootNode = ConvertToNodeModel(tree); return new GetMyNetworkTreeResponse { RootNode = rootNode, TotalMembers = CountNodes(tree), CurrentDepth = tree.CurrentDepth }; } public override async Task GetSubordinateTree(GetSubordinateTreeRequest request, ServerCallContext context) { // Get tree for a specific subordinate user var query = new GetNetworkTreeQuery { UserId = request.TargetUserId, MaxDepth = request.MaxDepth > 0 ? request.MaxDepth : 3 }; var tree = await _sender.Send(query, context.CancellationToken); if (tree == null) { return new GetMyNetworkTreeResponse { RootNode = null, TotalMembers = 0, CurrentDepth = 0 }; } var rootNode = ConvertToNodeModel(tree); return new GetMyNetworkTreeResponse { RootNode = rootNode, TotalMembers = CountNodes(tree), CurrentDepth = tree.CurrentDepth }; } public override async Task GetMyNetworkStatistics(Google.Protobuf.WellKnownTypes.Empty request, ServerCallContext context) { // Customer endpoint: resolve userId from JWT if (!long.TryParse(_currentUserService.UserId, out var userId) || userId <= 0) throw new RpcException(new Status(StatusCode.Unauthenticated, "کاربر احراز هویت نشده است")); var query = new GetNetworkStatisticsQuery { UserId = userId }; var stats = await _sender.Send(query, context.CancellationToken); return stats.Adapt(); } // Helper methods for tree conversion private NetworkTreeNodeModel ConvertToNodeModel(NetworkTreeDto dto) { var node = new NetworkTreeNodeModel { UserId = dto.UserId, UserName = $"{dto.FirstName} {dto.LastName}".Trim(), FullName = $"{dto.FirstName} {dto.LastName}".Trim(), NetworkLeg = dto.LegPosition.HasValue ? (int)dto.LegPosition.Value : 0, NetworkLevel = dto.CurrentDepth, Level = dto.CurrentDepth, IsActive = dto.IsClubActive, IsClubActive = dto.IsClubActive, ReferralCode = dto.ReferralCode ?? "", Mobile = dto.Mobile ?? "", Position = dto.LegPosition.HasValue ? dto.LegPosition.Value.ToString() : "Root" }; if (dto.ClubActivatedAt.HasValue) { node.ClubActivatedAt = Google.Protobuf.WellKnownTypes.Timestamp.FromDateTime( DateTime.SpecifyKind(dto.ClubActivatedAt.Value, DateTimeKind.Utc)); } if (dto.UserCreated != null) { node.UserCreated = Google.Protobuf.WellKnownTypes.Timestamp.FromDateTime( dto.UserCreated.UtcDateTime); } if (dto.ActivationWeekDefinitionId.HasValue) { node.ActivationWeekDefinitionId = dto.ActivationWeekDefinitionId.Value; } node.IsActivatedInTargetWeek = dto.IsActivatedInTargetWeek; // Recursively convert children if (dto.LeftChild != null) { node.LeftChild = ConvertToNodeModel(dto.LeftChild); } if (dto.RightChild != null) { node.RightChild = ConvertToNodeModel(dto.RightChild); } return node; } private int CountNodes(NetworkTreeDto tree) { if (tree == null) return 0; return 1 + CountNodes(tree.LeftChild) + CountNodes(tree.RightChild); } }