using NATS.Server.JetStream;
using NATS.Server.JetStream.Api;
using NATS.Server.JetStream.Cluster;
using NATS.Server.JetStream.Models;
namespace NATS.Server.JetStream.Tests;

public class JetStreamMetaGroupTests
{
    [Fact]
    public async Task Stream_create_requires_meta_group_commit()
    {
        await using var fixture = await MetaGroupTestFixture.StartAsync(nodes: 3);

        var result = await fixture.CreateStreamAsync("ORDERS", replicas: 3);
        result.Error.ShouldBeNull();

        var meta = await fixture.GetMetaStateAsync();
        meta.Streams.ShouldContain("ORDERS");
    }
}

internal sealed class MetaGroupTestFixture : IAsyncDisposable
{
    private readonly JetStreamMetaGroup _metaGroup;
    private readonly StreamManager _streamManager;
    private readonly ConsumerManager _consumerManager;
    private readonly JetStreamApiRouter _router;

    private MetaGroupTestFixture(JetStreamMetaGroup metaGroup, StreamManager streamManager, ConsumerManager consumerManager, JetStreamApiRouter router)
    {
        _metaGroup = metaGroup;
        _streamManager = streamManager;
        _consumerManager = consumerManager;
        _router = router;
    }

    public static Task<MetaGroupTestFixture> StartAsync(int nodes)
    {
        var meta = new JetStreamMetaGroup(nodes);
        var streamManager = new StreamManager(meta);
        var consumerManager = new ConsumerManager(meta);
        var router = new JetStreamApiRouter(streamManager, consumerManager, meta);
        return Task.FromResult(new MetaGroupTestFixture(meta, streamManager, consumerManager, router));
    }

    public Task<NATS.Server.JetStream.Api.JetStreamApiResponse> CreateStreamAsync(string name, int replicas)
    {
        var response = _streamManager.CreateOrUpdate(new StreamConfig
        {
            Name = name,
            Subjects = [name.ToLowerInvariant() + ".*"],
            Replicas = replicas,
        });
        return Task.FromResult(response);
    }

    public Task<MetaGroupState> GetMetaStateAsync() => Task.FromResult(_metaGroup.GetState());

    public Task<JetStreamApiResponse> RequestAsync(string subject, string payload)
    {
        return Task.FromResult(_router.Route(subject, System.Text.Encoding.UTF8.GetBytes(payload)));
    }

    public ValueTask DisposeAsync() => ValueTask.CompletedTask;
}
