using Kompas.Mcp.Core.Startup;

namespace Kompas.Mcp.Tests;

/// <summary>
/// Текст ошибки инструмента. SDK показывает клиенту сообщение только у McpException, поэтому
/// причину собирает фильтр — и она обязана называть инструмент и суть, а не тип исключения.
/// </summary>
[Trait("Category", "Unit")]
public sealed class ToolErrorTextTests
{
    [Fact]
    public void Message_names_the_tool_and_the_reason()
    {
        var text = ToolErrorText.Describe("extrude", new InvalidOperationException("Эскиз id=7 уже закрыт."));

        Assert.Contains("extrude", text, StringComparison.Ordinal);
        Assert.Contains("Эскиз id=7 уже закрыт.", text, StringComparison.Ordinal);
    }

    [Fact]
    public void Inner_exception_is_appended_as_the_underlying_cause()
    {
        var inner = new InvalidOperationException("ksTextEx вернул 0.");
        var outer = new InvalidOperationException("Примитив [0] (text) не построен.", inner);

        var text = ToolErrorText.Describe("sketch_add", outer);

        Assert.Contains("Примитив [0] (text) не построен.", text, StringComparison.Ordinal);
        Assert.Contains("ksTextEx вернул 0.", text, StringComparison.Ordinal);
    }

    [Fact]
    public void Single_wrapped_aggregate_is_unwrapped_to_the_real_cause()
    {
        var aggregate = new AggregateException(new KeyNotFoundException("Эскиз с id=42 не найден."));

        var text = ToolErrorText.Describe("extrude", aggregate);

        Assert.Contains("Эскиз с id=42 не найден.", text, StringComparison.Ordinal);
        Assert.DoesNotContain("One or more errors", text, StringComparison.Ordinal);
    }

    [Fact]
    public void Empty_message_falls_back_to_the_exception_type()
    {
        var text = ToolErrorText.Describe("hole", new TimeoutException(""));

        Assert.Contains("TimeoutException", text, StringComparison.Ordinal);
    }

    [Fact]
    public void Missing_tool_name_still_yields_a_readable_message()
    {
        var text = ToolErrorText.Describe(null, new ArgumentException("Радиус должен быть > 0."));

        Assert.Contains("Радиус должен быть > 0.", text, StringComparison.Ordinal);
        Assert.DoesNotContain("«»", text, StringComparison.Ordinal);
    }
}
