using MediatR;
using TakeoutSaaS.Application.App.Personal.Dto;
using TakeoutSaaS.Application.App.Personal.Queries;
using TakeoutSaaS.Application.App.Personal.Services;
using TakeoutSaaS.Domain.Tenants.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;

namespace TakeoutSaaS.Application.App.Personal.Handlers;

/// <summary>
/// 获取个人中心可见角色配置处理器。
/// </summary>
public sealed class GetPersonalVisibilityRoleConfigQueryHandler(
    PersonalContextService personalContextService,
    ITenantVisibilityRoleRuleRepository visibilityRoleRuleRepository)
    : IRequestHandler<GetPersonalVisibilityRoleConfigQuery, PersonalVisibilityRoleConfigDto>
{
    private static readonly string[] ManagerRoleCodes = ["tenant-owner", "tenant-admin"];
    private static readonly string[] DefaultVisibleRoleCodes = ["tenant-owner", "tenant-admin"];

    /// <summary>
    /// 处理查询。
    /// </summary>
    /// <param name="request">查询请求。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>可见角色配置。</returns>
    public async Task<PersonalVisibilityRoleConfigDto> Handle(GetPersonalVisibilityRoleConfigQuery request, CancellationToken cancellationToken)
    {
        // 1. 获取上下文并校验管理权限
        var context = personalContextService.GetRequiredContext();
        if (!HasAnyRole(context.RoleCodes, ManagerRoleCodes))
        {
            throw new BusinessException(ErrorCodes.Forbidden, "当前角色无权查看可见角色配置");
        }

        // 2. 查询并返回规则
        var rule = await visibilityRoleRuleRepository.FindByTenantIdAsync(context.TenantId, cancellationToken);
        if (rule is null)
        {
            return new PersonalVisibilityRoleConfigDto
            {
                TenantId = context.TenantId,
                QuotaVisibleRoleCodes = DefaultVisibleRoleCodes,
                BillingVisibleRoleCodes = DefaultVisibleRoleCodes,
                UpdatedBy = context.UserId,
                UpdatedAt = DateTime.UtcNow
            };
        }

        return new PersonalVisibilityRoleConfigDto
        {
            TenantId = rule.TenantId,
            QuotaVisibleRoleCodes = rule.QuotaVisibleRoleCodes,
            BillingVisibleRoleCodes = rule.BillingVisibleRoleCodes,
            UpdatedBy = rule.UpdatedBy ?? context.UserId,
            UpdatedAt = rule.UpdatedAt ?? DateTime.UtcNow
        };
    }

    private static bool HasAnyRole(IReadOnlyList<string> currentRoles, IReadOnlyList<string> allowedRoles)
    {
        // 1. 归一化当前角色
        var roleSet = currentRoles
            .Where(static x => !string.IsNullOrWhiteSpace(x))
            .Select(static x => x.Trim())
            .ToHashSet(StringComparer.OrdinalIgnoreCase);

        // 2. 判断是否命中允许角色
        return allowedRoles.Any(roleSet.Contains);
    }
}
