using Eshop.Application.Auth;
using Eshop.Application.Common;
using Eshop.Infrastructure.Persistence;
using Microsoft.AspNetCore.Identity;

namespace Eshop.Infrastructure.Identity;

public class AspNetIdentityUserAdministrationService(
    UserManager<UserEntity> users,
    RoleManager<IdentityRole> roles) : IUserAdministrationService
{
    public async Task<IReadOnlyList<UserWithRolesDto>> GetAllUsersWithRolesAsync(
        CancellationToken cancellationToken)
    {
        var allRoles = roles.Roles.Select(r => r.Name!).ToList();
        var viewModels = new List<UserWithRolesDto>();

        foreach (var user in users.Users.ToList())
        {
            var userRoles = await users.GetRolesAsync(user);
            viewModels.Add(ToDto(user, userRoles, allRoles));
        }

        return viewModels;
    }

    public async Task<UserWithRolesDto?> GetUserWithRolesAsync(
        string userId,
        CancellationToken cancellationToken)
    {
        var user = await users.FindByIdAsync(userId);
        if (user is null)
            return null;

        var userRoles = await users.GetRolesAsync(user);
        var allRoles = roles.Roles.Select(r => r.Name!).ToList();
        return ToDto(user, userRoles, allRoles);
    }

    public async Task<ServiceResult> UpdateUserRolesAsync(
        string userId,
        IReadOnlyList<string> selectedRoles,
        CancellationToken cancellationToken)
    {
        var user = await users.FindByIdAsync(userId);
        if (user is null)
            return ServiceResult.Failure("User not found.");

        var currentRoles = await users.GetRolesAsync(user);
        await users.RemoveFromRolesAsync(user, currentRoles);

        if (selectedRoles.Count <= 0) return ServiceResult.Ok();
        
        var result = await users.AddToRolesAsync(user, selectedRoles);
        return !result.Succeeded ? ServiceResult.Failure(result.Errors.Select(e => e.Description)) : ServiceResult.Ok();
    }

    private static UserWithRolesDto ToDto(
        UserEntity user,
        IList<string> userRoles,
        IList<string> allRoles) =>
        new(
            new UserDto(user.Id, user.UserName!, user.Email!),
            userRoles.ToList(),
            allRoles.ToList());
}
