namespace CMSMicroservice.Application.NetworkMembershipCQ.Queries.GetNetworkTree;

public class GetNetworkTreeQueryHandler : IRequestHandler<GetNetworkTreeQuery, NetworkTreeDto?>
{
    private readonly IApplicationDbContext _context;

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

    public async Task<NetworkTreeDto?> Handle(GetNetworkTreeQuery request, CancellationToken cancellationToken)
    {
        var rootUser = await _context.Users
            .AsNoTracking()
            .FirstOrDefaultAsync(x => x.Id == request.UserId, cancellationToken);

        if (rootUser == null)
        {
            return null;
        }

        var tree = await BuildTree(rootUser.Id, request.MaxDepth, 0, cancellationToken);
        return tree;
    }

    private async Task<NetworkTreeDto> BuildTree(long userId, int maxDepth, int currentDepth, CancellationToken cancellationToken)
    {
        var user = await _context.Users
            .AsNoTracking()
            .FirstOrDefaultAsync(x => x.Id == userId, cancellationToken);

        if (user == null)
        {
            throw new NotFoundException(nameof(User), userId);
        }

        var node = new NetworkTreeDto
        {
            UserId = user.Id,
            Mobile = user.Mobile,
            FirstName = user.FirstName,
            LastName = user.LastName,
            LegPosition = user.LegPosition,
            CurrentDepth = currentDepth
        };

        // اگر به حداکثر عمق رسیدیم، دیگر فرزندان را نمی‌خوانیم
        if (currentDepth >= maxDepth)
        {
            return node;
        }

        // پیدا کردن فرزند چپ
        var leftChild = await _context.Users
            .AsNoTracking()
            .FirstOrDefaultAsync(x => x.NetworkParentId == userId && x.LegPosition == NetworkLeg.Left,
                cancellationToken);

        if (leftChild != null)
        {
            node.LeftChild = await BuildTree(leftChild.Id, maxDepth, currentDepth + 1, cancellationToken);
        }

        // پیدا کردن فرزند راست
        var rightChild = await _context.Users
            .AsNoTracking()
            .FirstOrDefaultAsync(x => x.NetworkParentId == userId && x.LegPosition == NetworkLeg.Right,
                cancellationToken);

        if (rightChild != null)
        {
            node.RightChild = await BuildTree(rightChild.Id, maxDepth, currentDepth + 1, cancellationToken);
        }

        return node;
    }
}
