using MediatR;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using IamService.Domain.AggregatesModel.RoleAggregate;
using IamService.Infrastructure;

namespace IamService.API.Application.Queries.Roles;

/// <summary>
/// EN: Handler for GetRolesQuery — includes user count and permissions per role.
/// VI: Handler cho GetRolesQuery — bao gồm số user và permissions mỗi role.
/// </summary>
public class GetRolesQueryHandler : IRequestHandler<GetRolesQuery, GetRolesQueryResult>
{
    private readonly RoleManager<ApplicationRole> _roleManager;
    private readonly IamServiceContext _dbContext;
    private readonly ILogger<GetRolesQueryHandler> _logger;

    public GetRolesQueryHandler(
        RoleManager<ApplicationRole> roleManager,
        IamServiceContext dbContext,
        ILogger<GetRolesQueryHandler> logger)
    {
        _roleManager = roleManager;
        _dbContext = dbContext;
        _logger = logger;
    }

    public async Task<GetRolesQueryResult> Handle(GetRolesQuery request, CancellationToken cancellationToken)
    {
        _logger.LogInformation("Getting roles - Page: {Page}, Size: {Size}", request.PageNumber, request.PageSize);

        var query = _roleManager.Roles;
        var totalCount = await query.CountAsync(cancellationToken);

        // EN: Load roles with user count
        // VI: Tải roles với số lượng user
        var rolesWithCount = await query
            .OrderBy(r => r.Name)
            .Skip((request.PageNumber - 1) * request.PageSize)
            .Take(request.PageSize)
            .GroupJoin(
                _dbContext.UserRoles,
                role => role.Id,
                userRole => userRole.RoleId,
                (role, userRoles) => new { role, UserCount = userRoles.Count() })
            .ToListAsync(cancellationToken);

        // EN: Batch-fetch permissions from role_claims for all loaded roles
        // VI: Batch-fetch permissions từ role_claims cho tất cả roles đã tải
        var roleIds = rolesWithCount.Select(r => r.role.Id).ToList();
        var permissionsByRole = await _dbContext.RoleClaims
            .Where(rc => roleIds.Contains(rc.RoleId) && rc.ClaimType == "permission")
            .GroupBy(rc => rc.RoleId)
            .ToDictionaryAsync(
                g => g.Key,
                g => (IReadOnlyList<string>)g.Select(rc => rc.ClaimValue!).ToList(),
                cancellationToken);

        var roles = rolesWithCount.Select(r => new RoleDto(
            r.role.Id,
            r.role.Name!,
            r.role.Description,
            r.role.IsSystemRole,
            r.role.CreatedAt,
            r.UserCount,
            permissionsByRole.GetValueOrDefault(r.role.Id, Array.Empty<string>())
        )).ToList();

        return new GetRolesQueryResult(roles, totalCount, request.PageNumber, request.PageSize);
    }
}
