using ZB.MOM.WW.Auth.ApiKeys;

namespace ZB.MOM.WW.Auth.ApiKeys.Tests;

public class ApiKeyParserTests
{
    // --- basic happy path ---

    [Fact]
    public void TryParse_SimpleToken_ReturnsParsedKey()
    {
        var result = ApiKeyParser.TryParse("mxgw_alice_SECRET", "mxgw");

        Assert.NotNull(result);
        Assert.Equal("alice", result.KeyId);
        Assert.Equal("SECRET", result.Secret);
    }

    [Fact]
    public void TryParse_BearerPrefixCaseInsensitive_ReturnsParsedKey()
    {
        var result = ApiKeyParser.TryParse("Bearer mxgw_alice_SEC_RET", "mxgw");

        Assert.NotNull(result);
        Assert.Equal("alice", result.KeyId);
        Assert.Equal("SEC_RET", result.Secret);
    }

    [Fact]
    public void TryParse_BearerLowercase_ReturnsParsedKey()
    {
        var result = ApiKeyParser.TryParse("bearer mxgw_alice_SECRET", "mxgw");

        Assert.NotNull(result);
        Assert.Equal("alice", result.KeyId);
        Assert.Equal("SECRET", result.Secret);
    }

    [Fact]
    public void TryParse_SecretContainsUnderscores_SecretIsEverythingAfterFirstSplit()
    {
        var result = ApiKeyParser.TryParse("mxgw_k1_a_b_c", "mxgw");

        Assert.NotNull(result);
        Assert.Equal("k1", result.KeyId);
        Assert.Equal("a_b_c", result.Secret);
    }

    // --- custom prefix ---

    [Fact]
    public void TryParse_CustomPrefix_Works()
    {
        var result = ApiKeyParser.TryParse("myapp_user42_s3cr3t", "myapp");

        Assert.NotNull(result);
        Assert.Equal("user42", result.KeyId);
        Assert.Equal("s3cr3t", result.Secret);
    }

    [Fact]
    public void TryParse_CustomPrefix_WithBearer()
    {
        var result = ApiKeyParser.TryParse("Bearer myapp_user42_s3cr3t", "myapp");

        Assert.NotNull(result);
        Assert.Equal("user42", result.KeyId);
        Assert.Equal("s3cr3t", result.Secret);
    }

    // --- rejection cases ---

    [Fact]
    public void TryParse_WrongPrefix_ReturnsNull()
    {
        var result = ApiKeyParser.TryParse("zzz_a_b", "mxgw");

        Assert.Null(result);
    }

    [Fact]
    public void TryParse_NoDelimiters_ReturnsNull()
    {
        var result = ApiKeyParser.TryParse("nodelims", "mxgw");

        Assert.Null(result);
    }

    [Fact]
    public void TryParse_NullInput_ReturnsNull()
    {
        var result = ApiKeyParser.TryParse(null, "mxgw");

        Assert.Null(result);
    }

    [Fact]
    public void TryParse_EmptyInput_ReturnsNull()
    {
        var result = ApiKeyParser.TryParse("", "mxgw");

        Assert.Null(result);
    }

    [Fact]
    public void TryParse_WhitespaceInput_ReturnsNull()
    {
        var result = ApiKeyParser.TryParse("   ", "mxgw");

        Assert.Null(result);
    }

    [Fact]
    public void TryParse_OnlyPrefix_NoKeyIdOrSecret_ReturnsNull()
    {
        // "mxgw_" — prefix present but no key id segment
        var result = ApiKeyParser.TryParse("mxgw_", "mxgw");

        Assert.Null(result);
    }

    [Fact]
    public void TryParse_PrefixAndKeyIdButNoSecret_ReturnsNull()
    {
        // "mxgw_alice" — no second underscore after key id
        var result = ApiKeyParser.TryParse("mxgw_alice", "mxgw");

        Assert.Null(result);
    }

    [Fact]
    public void TryParse_PrefixAndUnderscoreButEmptySecret_ReturnsNull()
    {
        // "mxgw_alice_" — secret is empty
        var result = ApiKeyParser.TryParse("mxgw_alice_", "mxgw");

        Assert.Null(result);
    }

    // --- generator↔parser round-trip ---

    [Fact]
    public void TryParse_RealGeneratedSecret_RoundTripsKeyIdAndFullSecret()
    {
        // ApiKeySecretGenerator produces URL-safe base64 which may contain '_'.
        // The parser must preserve the full secret even when it contains underscores.
        string secret = ApiKeySecretGenerator.NewSecret();
        string token = $"mxgw_someid_{secret}";

        var result = ApiKeyParser.TryParse(token, "mxgw");

        Assert.NotNull(result);
        Assert.Equal("someid", result!.KeyId);
        Assert.Equal(secret, result.Secret);
    }
}
