using Shouldly;
using ZB.MOM.NatsNet.Server;
using ZB.MOM.NatsNet.Server.Internal;

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

public sealed partial class ConcurrencyTests1
{
    [Fact] // T:2469
    public async Task NoRaceRoutePoolAndPerAccountConfigReload_ShouldSucceed()
    {
        var (server, err) = NatsServer.NewServer(new ServerOptions());
        err.ShouldBeNull();
        server.ShouldNotBeNull();

        var logger = new ConcurrencyCaptureLogger();
        server!.SetLogger(logger, false, false);

        var cts = new CancellationTokenSource(TimeSpan.FromSeconds(1));
        var publishTask = Task.Run(async () =>
        {
            while (!cts.Token.IsCancellationRequested)
            {
                server.RateLimitWarnf("route pool update for account {0}", "A");
                await Task.Delay(1, cts.Token);
            }
        }, cts.Token);

        var reloadTask = Task.Run(async () =>
        {
            while (!cts.Token.IsCancellationRequested)
            {
                var opts = server.GetOpts();
                opts.Cluster.PoolSize = opts.Cluster.PoolSize == 2 ? 3 : 2;
                opts.Cluster.PinnedAccounts = opts.Cluster.PoolSize == 2 ? ["A"] : ["A", "B"];
                server.SetOpts(opts);
                await Task.Delay(1, cts.Token);
            }
        }, cts.Token);

        await Task.WhenAll(
            publishTask.ContinueWith(_ => { }, TaskScheduler.Default),
            reloadTask.ContinueWith(_ => { }, TaskScheduler.Default));

        server.GetOpts().Cluster.PoolSize.ShouldBeOneOf(2, 3);
    }

    private sealed class ConcurrencyCaptureLogger : INatsLogger
    {
        public void Noticef(string format, params object[] args)
        {
        }

        public void Warnf(string format, params object[] args)
        {
        }

        public void Fatalf(string format, params object[] args)
        {
        }

        public void Errorf(string format, params object[] args)
        {
        }

        public void Debugf(string format, params object[] args)
        {
        }

        public void Tracef(string format, params object[] args)
        {
        }
    }
}
