namespace CMSMicroservice.Application.NetworkMembershipCQ.Queries.GetUserNetworkPosition;

public class GetUserNetworkPositionQueryHandler : IRequestHandler<GetUserNetworkPositionQuery, UserNetworkPositionDto?>
{
    private readonly IApplicationDbContext _context;

    public GetUserNetworkPositionQueryHandler(IApplicationDbContext context)
    {
        _context = context;
    }

    public async Task<UserNetworkPositionDto?> 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,
            HasPurchasedPackage = user.PackagePurchaseMethod != PackagePurchaseMethod.None,
            
            // آمار مالی
            TotalEarnedCommission = commissionStats?.TotalAmount ?? 0,
            TotalPaidCommission = commissionStats?.PaidAmount ?? 0,
            PendingCommission = commissionStats?.PendingAmount ?? 0,
            TotalBalancesEarned = commissionStats?.TotalBalances ?? 0,
            
            // آمار فعالیت
            ActiveMembersInNetwork = activeCount,
            InactiveMembersInNetwork = inactiveCount
        };
    }

    /// <summary>
    /// محاسبه تعداد اعضای یک شاخه (چپ یا راست) به صورت بازگشتی
    /// </summary>
    private async Task<int> 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 برای خود فرزند
    }

    /// <summary>
    /// محاسبه حداکثر عمق شبکه
    /// </summary>
    private async Task<int> GetMaxNetworkDepthAsync(long userId, CancellationToken cancellationToken)
    {
        var maxDepth = 0;
        var currentLevelIds = new List<long> { 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;
    }

    /// <summary>
    /// دریافت تمام ID های زیرمجموعه یک کاربر
    /// </summary>
    private async Task<List<long>> GetAllDescendantIdsAsync(long userId, CancellationToken cancellationToken)
    {
        var allDescendants = new List<long>();
        var currentLevelIds = new List<long> { 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;
    }
}
