using ClawdDotNet.Tools.DirectAPI;
using Shouldly;

namespace ClawdDotNet.Tools.Tests.DirectAPI;

/// <summary>
/// S3 aus der Bestandsaufnahme: Die abgerufene URL ging als "source" an das Modell —
/// inklusive apikey= im Query-String. Der Schlüssel landete damit im Kontext, wurde
/// bei jedem Folgeschritt erneut gesendet und in ChatContext.json geschrieben.
/// </summary>
public sealed class UrlSanitizerTests
{
    private const string Secret = "GEHEIM-abc123XYZ";

    [Theory]
    [InlineData("https://api.twelvedata.com/quote?symbol=NVDA&apikey=GEHEIM-abc123XYZ")]
    [InlineData("https://www.alphavantage.co/query?function=GLOBAL_QUOTE&symbol=X&apikey=GEHEIM-abc123XYZ")]
    [InlineData("https://api.example.com/v1?api_key=GEHEIM-abc123XYZ&x=1")]
    [InlineData("https://api.example.com/v1?token=GEHEIM-abc123XYZ")]
    [InlineData("https://api.example.com/v1?access_token=GEHEIM-abc123XYZ")]
    [InlineData("https://api.example.com/v1?KEY=GEHEIM-abc123XYZ")]
    [InlineData("https://api.example.com/v1?ApiKey=GEHEIM-abc123XYZ&other=2")]
    [InlineData("https://api.example.com/v1?secret=GEHEIM-abc123XYZ")]
    [InlineData("https://api.example.com/v1?a=1&apikey=GEHEIM-abc123XYZ#fragment")]
    public void Sensible_Parameter_werden_maskiert(string url)
    {
        var sanitized = UrlSanitizer.Sanitize(url);

        sanitized.ShouldNotContain(Secret);
        sanitized.ShouldContain("***");
    }

    [Fact]
    public void Harmlose_Parameter_bleiben_lesbar()
    {
        var sanitized = UrlSanitizer.Sanitize(
            "https://api.twelvedata.com/quote?symbol=NVDA&interval=1day&apikey=GEHEIM-abc123XYZ");

        sanitized.ShouldContain("symbol=NVDA");
        sanitized.ShouldContain("interval=1day");
        sanitized.ShouldContain("apikey=***");
    }

    [Fact]
    public void Der_Pfad_bleibt_erhalten()
    {
        var sanitized = UrlSanitizer.Sanitize("https://api.massive.com/v2/aggs/ticker/NVDA?apikey=x");

        sanitized.ShouldStartWith("https://api.massive.com/v2/aggs/ticker/NVDA?");
    }

    [Fact]
    public void Ein_Fragment_bleibt_erhalten()
    {
        var sanitized = UrlSanitizer.Sanitize("https://x.de/a?apikey=geheim#abschnitt");

        sanitized.ShouldEndWith("#abschnitt");
        sanitized.ShouldNotContain("geheim");
    }

    [Theory]
    [InlineData("https://api.example.com/v1")]
    [InlineData("https://api.example.com/v1?symbol=NVDA")]
    public void URLs_ohne_sensible_Parameter_bleiben_unveraendert(string url)
    {
        UrlSanitizer.Sanitize(url).ShouldBe(url);
    }

    [Theory]
    [InlineData(null)]
    [InlineData("")]
    [InlineData("   ")]
    public void Leere_Eingaben_fuehren_nicht_zu_einem_Fehler(string? url)
    {
        Should.NotThrow(() => UrlSanitizer.Sanitize(url));
    }

    [Fact]
    public void Ein_Parameter_ohne_Wert_stoert_nicht()
    {
        var sanitized = UrlSanitizer.Sanitize("https://x.de/a?flag&apikey=geheim");

        sanitized.ShouldContain("flag");
        sanitized.ShouldNotContain("geheim");
    }

    [Fact]
    public void Ein_Schluessel_als_Teil_eines_anderen_Namens_wird_nicht_faelschlich_maskiert()
    {
        // "monkey" enthält "key", ist aber kein sensibler Parameter.
        var sanitized = UrlSanitizer.Sanitize("https://x.de/a?monkey=banane");

        sanitized.ShouldBe("https://x.de/a?monkey=banane");
    }
}
