namespace CMSMicroservice.Application.NetworkMembershipCQ.Commands.MoveInNetwork;

public class MoveInNetworkCommandHandler : IRequestHandler<MoveInNetworkCommand, Unit>
{
    private readonly IApplicationDbContext _context;
    private readonly ICurrentUserService _currentUser;

    public MoveInNetworkCommandHandler(
        IApplicationDbContext context,
        ICurrentUserService currentUser)
    {
        _context = context;
        _currentUser = currentUser;
    }

    public async Task<Unit> Handle(MoveInNetworkCommand request, CancellationToken cancellationToken)
    {
        // بررسی وجود کاربر
        var user = await _context.Users
            .FirstOrDefaultAsync(x => x.Id == request.UserId, cancellationToken);

        if (user == null)
        {
            throw new NotFoundException(nameof(User), request.UserId);
        }

        // بررسی اینکه کاربر در شبکه باشد
        if (!user.NetworkParentId.HasValue)
        {
            throw new InvalidOperationException($"کاربر با شناسه {request.UserId} در شبکه عضو نیست");
        }

        // بررسی وجود والد جدید
        var newParent = await _context.Users
            .FirstOrDefaultAsync(x => x.Id == request.NewParentId, cancellationToken);

        if (newParent == null)
        {
            throw new NotFoundException(nameof(User), $"New Parent with Id {request.NewParentId}");
        }

        // بررسی اینکه والد جدید خود کاربر یا فرزندان او نباشد (جلوگیری از Loop)
        if (await IsDescendant(request.NewParentId, request.UserId, cancellationToken))
        {
            throw new InvalidOperationException("نمی‌توان کاربر را زیر فرزندان خودش جابجا کرد (ایجاد حلقه)");
        }

        // بررسی خالی بودن Leg جدید
        var legOccupied = await _context.Users
            .AnyAsync(x => x.NetworkParentId == request.NewParentId && 
                          x.LegPosition == request.NewLegPosition &&
                          x.Id != request.UserId,
                cancellationToken);

        if (legOccupied)
        {
            throw new InvalidOperationException(
                $"موقعیت {request.NewLegPosition} زیر والد {request.NewParentId} قبلاً پر شده است");
        }

        // ذخیره مقادیر قبلی برای History
        var oldParentId = user.NetworkParentId;
        var oldLegPosition = user.LegPosition;

        // جابجایی
        user.NetworkParentId = request.NewParentId;
        user.LegPosition = request.NewLegPosition;

        _context.Users.Update(user);
        await _context.SaveChangesAsync(cancellationToken);

        // ثبت تاریخچه
        var history = new NetworkMembershipHistory
        {
            UserId = request.UserId,
            OldParentId = oldParentId,
            NewParentId = request.NewParentId,
            OldLegPosition = oldLegPosition,
            NewLegPosition = request.NewLegPosition,
            Action = NetworkMembershipAction.Move,
            Reason = request.Reason ?? "جابجایی در شبکه",
            PerformedBy = "System" // TODO: باید از Current User گرفته شود
        };

        await _context.NetworkMembershipHistories.AddAsync(history, cancellationToken);
        await _context.SaveChangesAsync(cancellationToken);

        return Unit.Value;
    }

    /// <summary>
    /// بررسی می‌کند که آیا potentialDescendant فرزند (مستقیم یا غیرمستقیم) userId هست یا خیر
    /// </summary>
    private async Task<bool> IsDescendant(long potentialDescendantId, long userId, CancellationToken cancellationToken)
    {
        var current = await _context.Users
            .FirstOrDefaultAsync(x => x.Id == potentialDescendantId, cancellationToken);

        while (current?.NetworkParentId != null)
        {
            if (current.NetworkParentId == userId)
            {
                return true;
            }

            current = await _context.Users
                .FirstOrDefaultAsync(x => x.Id == current.NetworkParentId, cancellationToken);
        }

        return false;
    }
}
