namespace Brizco.Repository.Handlers.Complexes;

public class UpdateComplexUserCommandHandler : IRequestHandler<UpdateComplexUserCommand, bool>
{
    private readonly IRepositoryWrapper _repositoryWrapper;
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly RoleManager<ApplicationRole> _roleManager;

    public UpdateComplexUserCommandHandler(IRepositoryWrapper repositoryWrapper,
        UserManager<ApplicationUser> userManager,
        RoleManager<ApplicationRole> roleManager)
    {
        _repositoryWrapper = repositoryWrapper;
        _userManager = userManager;
        _roleManager = roleManager;
    }

    public async Task<bool> Handle(UpdateComplexUserCommand request, CancellationToken cancellationToken)
    {
        try
        {
            await _repositoryWrapper.BeginTransaction(cancellationToken);
            var complexUser = await _repositoryWrapper.SetRepository<ComplexUser>().TableNoTracking
                .FirstOrDefaultAsync(c => c.UserId == request.UserId && c.ComplexId == request.ComplexId , cancellationToken);
            if (complexUser == null)
                throw new AppException("ComplexUser not found", ApiResultStatusCode.NotFound);

            var complexUserRoles = await _repositoryWrapper.SetRepository<ComplexUserRole>()
                .TableNoTracking
                .Where(cur => cur.ComplexUserId == complexUser.Id)
                .ToListAsync(cancellationToken);

            var user = await _userManager.FindByIdAsync(complexUser.UserId.ToString());
            if (user == null)
                throw new AppException("User not found", ApiResultStatusCode.NotFound);


            foreach (var userRole in complexUserRoles.ToList())
            {
                if(request.RoleIds.Contains(userRole.RoleId))
                {
                    complexUserRoles.Remove(userRole);
                    request.RoleIds.Remove(userRole.RoleId);
                }
            }

            foreach (var userRole in complexUserRoles)
            {
                _repositoryWrapper.SetRepository<ComplexUserRole>().Delete(userRole);
                var role = await _roleManager.FindByIdAsync(userRole.RoleId.ToString());
                var result = await _userManager.RemoveFromRoleAsync(user, role.Name);
                if (!result.Succeeded)
                    throw new AppException(string.Join('|', result.Errors));
            }

            foreach (var roleId in request.RoleIds)
            {
                var role = await _roleManager.FindByIdAsync(roleId.ToString());
                var result = await _userManager.AddToRoleAsync(user, role.Name);
                if (!result.Succeeded)
                    throw new AppException(string.Join('|', result.Errors));
                var userRole = complexUser.AddRole(role.Id);
                _repositoryWrapper.SetRepository<ComplexUserRole>().Add(userRole);
            }

            await _repositoryWrapper.SaveChangesAsync(cancellationToken);
            await _repositoryWrapper.CommitAsync(cancellationToken);
            return true;
        }
        catch (Exception)
        {
            await _repositoryWrapper.RollBackAsync(cancellationToken);
            throw;
        }
    }
}