using CMSMicroservice.Domain.Events;
using CMSMicroservice.Application.Common.Interfaces;
using Microsoft.Extensions.Logging;

namespace CMSMicroservice.Application.UserCQ.Commands.CreateNewUser;

public class CreateNewUserCommandHandler : IRequestHandler<CreateNewUserCommand, CreateNewUserResponseDto>
{
    private readonly IApplicationDbContext _context;
    private readonly INetworkPlacementService _networkPlacementService;
    private readonly ILogger<CreateNewUserCommandHandler> _logger;

    public CreateNewUserCommandHandler(
        IApplicationDbContext context,
        INetworkPlacementService networkPlacementService,
        ILogger<CreateNewUserCommandHandler> logger)
    {
        _context = context;
        _networkPlacementService = networkPlacementService;
        _logger = logger;
    }

    public async Task<CreateNewUserResponseDto> Handle(CreateNewUserCommand request,
        CancellationToken cancellationToken)
    {
        var entity = request.Adapt<User>();
        entity.ReferralCode = UtilExtensions.Generate(digits: 10, firstDigitNonZero: true);

        // === تنظیم Network Binary Tree ===
        // اگر ParentId تنظیم شده، باید NetworkParentId و LegPosition هم Set بشن
        if (request.ParentId.HasValue)
        {
            // محاسبه LegPosition برای Binary Tree
            var legPosition = await _networkPlacementService.CalculateLegPositionAsync(
                request.ParentId.Value, 
                cancellationToken);

            if (legPosition.HasValue)
            {
                // Parent می‌تواند فرزند جدید بپذیرد
                entity.NetworkParentId = request.ParentId.Value;
                entity.LegPosition = legPosition.Value;
                
                _logger.LogInformation(
                    "User {UserId} placed in Binary Tree: Parent={ParentId}, Leg={Leg}",
                    entity.Id, entity.NetworkParentId, entity.LegPosition);
            }
            else
            {
                // Parent پر است! باید Auto-Placement کنیم یا Error بدیم
                _logger.LogWarning(
                    "Parent {ParentId} has no available leg! Finding alternative parent...",
                    request.ParentId.Value);

                var availableParent = await _networkPlacementService.FindAvailableParentAsync(
                    request.ParentId.Value, 
                    cancellationToken);

                if (availableParent.HasValue)
                {
                    var newLegPosition = await _networkPlacementService.CalculateLegPositionAsync(
                        availableParent.Value, 
                        cancellationToken);

                    entity.NetworkParentId = availableParent.Value;
                    entity.LegPosition = newLegPosition!.Value;
                    
                    _logger.LogInformation(
                        "User {UserId} auto-placed under alternative Parent={ParentId}, Leg={Leg}",
                        entity.Id, entity.NetworkParentId, entity.LegPosition);
                }
                else
                {
                    // هیچ جای خالی در Binary Tree پیدا نشد!
                    _logger.LogError(
                        "No available parent found in network for ParentId={ParentId}",
                        request.ParentId.Value);
                    
                    throw new InvalidOperationException(
                        $"شبکه Parent با شناسه {request.ParentId.Value} پر است و نمی‌تواند کاربر جدید بپذیرد.");
                }
            }
        }
        else
        {
            // کاربر Root است (بدون Parent)
            _logger.LogInformation("Creating root user without Parent");
        }

        await _context.Users.AddAsync(entity, cancellationToken);
        entity.AddDomainEvent(new CreateNewUserEvent(entity));
        await _context.SaveChangesAsync(cancellationToken);
        
        return entity.Adapt<CreateNewUserResponseDto>();
    }
}
