using ColaFlow.Modules.Identity.Application.Dtos;
using ColaFlow.Modules.Identity.Domain.Repositories;
using MediatR;

namespace ColaFlow.Modules.Identity.Application.Queries.ListTenantUsers;

public class ListTenantUsersQueryHandler(
    IUserTenantRoleRepository userTenantRoleRepository,
    IUserRepository userRepository)
    : IRequestHandler<ListTenantUsersQuery, PagedResultDto<UserWithRoleDto>>
{
    public async Task<PagedResultDto<UserWithRoleDto>> Handle(
        ListTenantUsersQuery request,
        CancellationToken cancellationToken)
    {
        var (roles, totalCount) = await userTenantRoleRepository.GetTenantUsersWithRolesAsync(
            request.TenantId,
            request.PageNumber,
            request.PageSize,
            request.SearchTerm,
            cancellationToken);

        // Optimized: Batch load all users in single query instead of N+1 queries
        // Note: role.UserId is a UserId value object with a .Value property that returns Guid
        var userIds = roles.Select(r => r.UserId.Value).ToList();
        var users = await userRepository.GetByIdsAsync(userIds, cancellationToken);

        // Create a dictionary for O(1) lookups (User.Id is Guid from Entity base class)
        var userDict = users.ToDictionary(u => u.Id, u => u);

        var userDtos = new List<UserWithRoleDto>();

        foreach (var role in roles)
        {
            // Use role.UserId.Value to get the Guid for dictionary lookup
            if (userDict.TryGetValue(role.UserId.Value, out var user))
            {
                userDtos.Add(new UserWithRoleDto(
                    user.Id,
                    user.Email.Value,
                    user.FullName.Value,
                    role.Role.ToString(),
                    role.AssignedAt,
                    user.EmailVerifiedAt.HasValue));
            }
        }

        var totalPages = (int)Math.Ceiling(totalCount / (double)request.PageSize);

        return new PagedResultDto<UserWithRoleDto>(
            userDtos,
            totalCount,
            request.PageNumber,
            request.PageSize,
            totalPages);
    }
}
