using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Localization;
using Sozsoft.Platform.Localization;
using Volo.Abp;
using Volo.Abp.Authorization;
using Volo.Abp.Authorization.Permissions;
using Volo.Abp.DependencyInjection;
namespace Sozsoft.Mcp;
///
/// Aracin arkasindaki platform servislerinden (wizard, custom component, ListForm verisi) ve sinif
/// duzeyindeki [Authorize]'dan gelen istisnalari istemcinin gorebilecegi mesaja cevirir. MCP'nin
/// kendi reddi istisna degildir, olarak doner. SDK cevrilmemis istisnayi
/// "An error occurred invoking" olarak iletir ve model neden reddedildigini bilemez. Yetki reddinde
/// eksik yetkiler adiyla, is kurali hatasinda () zaten
/// yerellestirilmis mesaj iletilir. Diger istisnalar cevrilmez: ic ayrinti (SQL, yigin) istemciye sizmaz.
///
public class McpToolErrorTranslator(
IPermissionChecker permissionChecker,
IStringLocalizer localizer) : ITransientDependency
{
public static bool CanTranslate(Exception exception)
=> exception is AbpAuthorizationException or UserFriendlyException;
public async Task TranslateAsync(Exception exception, string? toolName)
=> exception is AbpAuthorizationException authorization
? await DescribeMissingPermissionsAsync(authorization, toolName)
: exception.Message;
///
/// CheckAsync("...") reddi yetki adini tasir; [Authorize] attribute'u tasimaz. Ikinci
/// durumda aracin adi bilinen yetkileri kullanicinin yetkileriyle karsilastirilir.
///
private async Task DescribeMissingPermissionsAsync(AbpAuthorizationException exception, string? toolName)
{
var candidates = new List(McpToolNames.KnownPermissionsOf(toolName));
if (exception.Data["PolicyName"] is string policyName && !string.IsNullOrWhiteSpace(policyName))
{
candidates.Add(policyName);
}
var grants = await permissionChecker.IsGrantedAsync([.. candidates.Distinct(StringComparer.Ordinal)]);
var missing = grants.Result
.Where(result => result.Value != PermissionGrantResult.Granted)
.Select(result => McpPermissionText.Describe(localizer, result.Key))
.ToList();
var target = toolName ?? McpConsts.EndpointPath;
return missing.Count == 0
? localizer[McpErrorCodes.PermissionDeniedUnspecified, target]
: localizer[McpErrorCodes.PermissionDenied, target, string.Join(", ", missing)];
}
}