using System.Security.Cryptography;
using ZB.MOM.WW.Secrets.Abstractions;
using ZB.MOM.WW.Secrets.Cli.Interactive;
using ZB.MOM.WW.Secrets.MasterKey;

namespace ZB.MOM.WW.Secrets.Tests.Cli.Interactive;

/// <summary>
/// Pins <see cref="LiteralMasterKeyProvider"/> — the operator-pasted-key provider used to recover a
/// locked-out session — to the family's key contract: 32-byte enforcement and, critically, a
/// <see cref="IMasterKeyProvider.KekId"/> derived identically to the configured providers so a key
/// entered by hand can decrypt (and re-wrap) rows another provider kind sealed.
/// </summary>
[Collection("Process environment")]
public sealed class LiteralMasterKeyProviderTests
{
    private static string NewKeyBase64()
    {
        byte[] key = new byte[32];
        RandomNumberGenerator.Fill(key);
        return Convert.ToBase64String(key);
    }

    [Fact]
    public void Accepts_base64_32_byte_key()
    {
        string b64 = NewKeyBase64();

        var sut = new LiteralMasterKeyProvider(b64);

        Assert.Equal(32, sut.GetMasterKey().Length);
        Assert.StartsWith("sha256:", sut.KekId);
    }

    [Fact]
    public void Rejects_wrong_length()
    {
        string sixteenBytes = Convert.ToBase64String(new byte[16]);

        Assert.Throws<ArgumentException>(() => new LiteralMasterKeyProvider(sixteenBytes));
    }

    [Fact]
    public void Derives_same_kekid_as_environment_provider_for_same_material()
    {
        byte[] key = new byte[32];
        RandomNumberGenerator.Fill(key);
        string b64 = Convert.ToBase64String(key);
        string envVar = $"ZB_TEST_KEK_{Guid.NewGuid():N}";
        Environment.SetEnvironmentVariable(envVar, b64);
        try
        {
            IMasterKeyProvider environment = MasterKeyProviderFactory.Create(new MasterKeyOptions
            {
                Source = MasterKeySource.Environment,
                EnvVarName = envVar,
            });
            var literal = new LiteralMasterKeyProvider(b64);

            Assert.Equal(environment.KekId, literal.KekId);
        }
        finally
        {
            Environment.SetEnvironmentVariable(envVar, null);
        }
    }

    [Fact]
    public void Explicit_kekid_wins()
    {
        var sut = new LiteralMasterKeyProvider(NewKeyBase64(), "kek:operator-override");

        Assert.Equal("kek:operator-override", sut.KekId);
    }
}
