using MediatR;
using TakeoutSaaS.Application.Identity.Contracts;
using TakeoutSaaS.Application.Identity.Queries;
using TakeoutSaaS.Domain.Identity.Repositories;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.Identity.Handlers;

/// <summary>
/// 权限树查询处理器。
/// </summary>
public sealed class PermissionTreeQueryHandler(
    IPermissionRepository permissionRepository,
    ITenantProvider tenantProvider)
    : IRequestHandler<PermissionTreeQuery, IReadOnlyList<PermissionTreeDto>>
{
    /// <summary>
    /// 构建权限树。
    /// </summary>
    /// <param name="request">查询参数。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>权限树列表。</returns>
    public async Task<IReadOnlyList<PermissionTreeDto>> Handle(PermissionTreeQuery request, CancellationToken cancellationToken)
    {
        // 1. 获取租户上下文并查询权限
        var tenantId = tenantProvider.GetCurrentTenantId();
        var permissions = await permissionRepository.SearchAsync(tenantId, request.Keyword, cancellationToken);

        // 2. 构建节点映射与父子分组
        var nodeMap = permissions.ToDictionary(
            x => x.Id,
            x => new PermissionTreeDto
            {
                Id = x.Id,
                TenantId = x.TenantId,
                ParentId = x.ParentId,
                SortOrder = x.SortOrder,
                Type = x.Type,
                Name = x.Name,
                Code = x.Code,
                Description = x.Description,
                Children = Array.Empty<PermissionTreeDto>()
            });
        var childrenLookup = permissions
            .GroupBy(x => x.ParentId)
            .ToDictionary(g => g.Key, g => g.OrderBy(c => c.SortOrder).ThenBy(c => c.Id).Select(c => c.Id).ToList());

        // 3. 递归组装树，确保子节点引用最新
        List<PermissionTreeDto> Build(long parentId)
        {
            if (!childrenLookup.TryGetValue(parentId, out var childIds))
            {
                return [];
            }

            var result = new List<PermissionTreeDto>(childIds.Count);
            foreach (var childId in childIds)
            {
                if (!nodeMap.TryGetValue(childId, out var child))
                {
                    continue;
                }

                var withChildren = child with { Children = Build(child.Id) };
                result.Add(withChildren);
            }

            return result;
        }

        // 4. 返回根节点集合
        var roots = Build(0);
        return roots;
    }
}
