using System.Numerics;
using Shouldly;
using ZB.MOM.NatsNet.Server;

namespace ZB.MOM.NatsNet.Server.Tests.JetStream;

public sealed class NatsStreamMessageHeadersTests
{
    [Fact]
    public void ParseMessageTTL_NeverValue_ReturnsMinusOne()
    {
        var (ttl, error) = NatsStream.ParseMessageTTL("never");

        error.ShouldBeNull();
        ttl.ShouldBe(-1);
    }

    [Fact]
    public void GetMessageIncr_ValidHeader_ReturnsParsedValue()
    {
        var hdr = NatsMessageHeaders.GenHeader(null, NatsHeaderConstants.JsMessageIncr, "42");

        var (value, ok) = NatsStream.GetMessageIncr(hdr);

        ok.ShouldBeTrue();
        value.ShouldBe(new BigInteger(42));
    }

    [Fact]
    public void GetMessageSchedule_InvalidPattern_ReturnsNotOk()
    {
        var hdr = NatsMessageHeaders.GenHeader(null, NatsHeaderConstants.JsSchedulePattern, "invalid");

        var (schedule, ok) = NatsStream.GetMessageSchedule(hdr);

        ok.ShouldBeFalse();
        schedule.ShouldBe(default);
    }

    [Fact]
    public void SetupStore_MemoryStorage_CreatesMemStore()
    {
        var stream = CreateStream(duplicates: TimeSpan.FromSeconds(1));

        var error = stream.SetupStore(null);

        error.ShouldBeNull();
        stream.Store.ShouldNotBeNull();
        stream.Store!.Type().ShouldBe(StorageType.MemoryStorage);
    }

    [Fact]
    public void StoreMsgIdAndPurge_ExpiredEntry_RemovesEntry()
    {
        var stream = CreateStream(duplicates: TimeSpan.FromMilliseconds(50));
        var oldTs = (DateTimeOffset.UtcNow - TimeSpan.FromSeconds(1)).ToUnixTimeMilliseconds() * 1_000_000L;
        stream.StoreMsgId(new NatsStream.DedupeEntry { Id = "id-1", Seq = 1, TimestampNanos = oldTs });

        stream.NumMsgIds().ShouldBe(1);
        stream.CheckMsgId("id-1").ShouldNotBeNull();

        stream.PurgeMsgIds();

        stream.NumMsgIds().ShouldBe(0);
        stream.CheckMsgId("id-1").ShouldBeNull();
    }

    private static NatsStream CreateStream(TimeSpan duplicates)
    {
        var account = new Account { Name = "A" };
        var config = new StreamConfig
        {
            Name = "S",
            Storage = StorageType.MemoryStorage,
            Duplicates = duplicates,
        };
        return new NatsStream(account, config, DateTime.UtcNow);
    }
}
