using ClawdDotNet.Core.Engine;
using ClawdDotNet.Core.Tests.Infrastructure;
using Shouldly;

namespace ClawdDotNet.Core.Tests.Engine;

/// <summary>
/// T2 aus der Token-Analyse: Ein einzelnes Tool-Ergebnis konnte den Kontext sprengen.
/// Ein WebFetch mit dem Standardlimit von 512 KB entspricht rund 130.000 Tokens in
/// EINER Antwort — die Compaction greift erst danach, bezahlt ist der Request längst.
/// </summary>
public sealed class ToolResultTruncationTests
{
    [Fact]
    public async Task Ein_riesiges_Toolergebnis_wird_gekappt_bevor_es_in_den_Kontext_geht()
    {
        var riesig = new string('x', 500_000);
        var fixture = new EngineFixture().WithTool(FakeTool.Returning(riesig));
        var agent = fixture.AddAgent("agent-trunc", "TestTool");
        agent.MaxToolResultChars = 16_000;

        fixture.Client
            .RespondsWithToolCall("TestTool")
            .RespondsWithText("Fertig");

        await fixture.Engine.ChatAsync(agent, "Hol die Daten", "test-instance", default);

        var context = fixture.Engine.GetChatContext(agent.AgentId);
        var toolMessage = context.Single(m => m.Role == "tool");

        toolMessage.Content!.Length.ShouldBeLessThan(20_000);
        toolMessage.Content.ShouldContain("gekürzt");
    }

    [Fact]
    public async Task Ein_kleines_Toolergebnis_bleibt_unveraendert()
    {
        const string klein = "Alles in Ordnung.";
        var fixture = new EngineFixture().WithTool(FakeTool.Returning(klein));
        var agent = fixture.AddAgent("agent-klein", "TestTool");

        fixture.Client
            .RespondsWithToolCall("TestTool")
            .RespondsWithText("Fertig");

        await fixture.Engine.ChatAsync(agent, "Prüfe", "test-instance", default);

        var context = fixture.Engine.GetChatContext(agent.AgentId);
        context.Single(m => m.Role == "tool").Content.ShouldBe(klein);
    }

    [Theory]
    [InlineData(100, 50)]
    [InlineData(1_000, 999)]
    [InlineData(50_000, 16_000)]
    public void Gekappte_Ergebnisse_nennen_die_Menge_der_entfallenen_Zeichen(int length, int limit)
    {
        var result = AgentEngine.TruncateToolResult(new string('a', length), limit);

        result.ShouldStartWith(new string('a', limit));
        result.ShouldContain((length - limit).ToString("N0"));
    }

    [Fact]
    public void Ohne_Limit_wird_nicht_gekappt()
    {
        var original = new string('a', 100_000);

        AgentEngine.TruncateToolResult(original, 0).ShouldBe(original);
    }

    [Fact]
    public void Genau_auf_der_Grenze_wird_nicht_gekappt()
    {
        var original = new string('a', 1_000);

        AgentEngine.TruncateToolResult(original, 1_000).ShouldBe(original);
    }
}
