namespace Kompas.Mcp.Core.Startup;

/// <summary>
/// Текст ошибки инструмента для клиента. MCP-SDK показывает сообщение исключения только у
/// <c>McpException</c>, всё остальное подменяет на «An error occurred invoking '&lt;tool&gt;'» —
/// а для агента ценна как раз причина: какого параметра не хватило и что делать дальше.
/// Форматирование живёт в Core, чтобы покрываться unit-тестами без MCP-хоста.
/// </summary>
public static class ToolErrorText
{
    /// <summary>Собрать сообщение: имя инструмента, причина и вложенные причины (без стека).</summary>
    public static string Describe(string? toolName, Exception exception)
    {
        ArgumentNullException.ThrowIfNull(exception);

        var reasons = new List<string>(3);
        for (var e = Unwrap(exception); e is not null && reasons.Count < 3; e = e.InnerException)
        {
            var message = (e.Message ?? "").Trim();
            // Служебный текст обёрток («One or more errors occurred») агенту ничего не говорит.
            if (message.Length == 0 || e is AggregateException) continue;
            if (!reasons.Contains(message)) reasons.Add(message);
        }

        if (reasons.Count == 0) reasons.Add(exception.GetType().Name);

        var where = string.IsNullOrWhiteSpace(toolName) ? "Инструмент" : $"Инструмент «{toolName}»";
        return $"{where} не выполнен: {string.Join(" ← ", reasons)}";
    }

    /// <summary>Развернуть агрегаты диспетчера: настоящая причина лежит внутри.</summary>
    private static Exception Unwrap(Exception exception)
        => exception is AggregateException aggregate && aggregate.InnerExceptions.Count == 1
            ? Unwrap(aggregate.InnerExceptions[0])
            : exception;
}
