using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Options;
using ZB.MOM.WW.MxGateway.Server.Configuration;
using ZB.MOM.WW.MxGateway.Server.Security.Authentication;

namespace ZB.MOM.WW.MxGateway.Tests.Security.Authentication;

public sealed class ApiKeySecretHasherTests
{
    /// <summary>
    /// Verifies identical pepper and secret produce identical hashes.
    /// </summary>
    [Fact]
    public void HashSecret_SamePepperAndSecret_ReturnsSameHash()
    {
        ApiKeySecretHasher hasher = CreateHasher("pepper-one");

        byte[] firstHash = hasher.HashSecret("raw-secret");
        byte[] secondHash = hasher.HashSecret("raw-secret");

        Assert.Equal(firstHash, secondHash);
        Assert.NotEqual("raw-secret"u8.ToArray(), firstHash);
    }

    /// <summary>
    /// Verifies different pepper values produce different hashes.
    /// </summary>
    [Fact]
    public void HashSecret_DifferentPepper_ReturnsDifferentHash()
    {
        byte[] firstHash = CreateHasher("pepper-one").HashSecret("raw-secret");
        byte[] secondHash = CreateHasher("pepper-two").HashSecret("raw-secret");

        Assert.NotEqual(firstHash, secondHash);
    }

    /// <summary>
    /// Verifies missing pepper throws an exception.
    /// </summary>
    [Fact]
    public void HashSecret_MissingPepper_Throws()
    {
        ApiKeySecretHasher hasher = CreateHasher(pepper: null);

        Assert.Throws<ApiKeyPepperUnavailableException>(() => hasher.HashSecret("raw-secret"));
    }

    private static ApiKeySecretHasher CreateHasher(string? pepper)
    {
        Dictionary<string, string?> values = [];

        if (pepper is not null)
        {
            values["TestPepper"] = pepper;
        }

        IConfigurationRoot configuration = new ConfigurationBuilder()
            .AddInMemoryCollection(values)
            .Build();

        GatewayOptions options = new()
        {
            Authentication = new AuthenticationOptions
            {
                PepperSecretName = "TestPepper"
            }
        };

        return new ApiKeySecretHasher(configuration, Options.Create(options));
    }
}
