using Microsoft.Extensions.Logging.Abstractions;
using NATS.Server.Configuration;

namespace NATS.Server.Tests;

public class JetStreamClusterReloadTests
{
    [Fact]
    public async Task Reload_rejects_non_reloadable_jetstream_storage_change()
    {
        await using var fixture = await ConfigReloadFixture.StartJetStreamAsync();

        var ex = await Should.ThrowAsync<InvalidOperationException>(() => fixture.ReloadAsync("jetstream { store_dir: '/new' }"));
        ex.Message.ShouldContain("requires restart");
    }
}

internal sealed class ConfigReloadFixture : IAsyncDisposable
{
    private readonly string _configPath;
    private readonly NatsServer _server;

    private ConfigReloadFixture(string configPath, NatsServer server)
    {
        _configPath = configPath;
        _server = server;
    }

    public static Task<ConfigReloadFixture> StartJetStreamAsync()
    {
        var configPath = Path.Combine(Path.GetTempPath(), $"natsdotnet-reload-{Guid.NewGuid():N}.conf");
        File.WriteAllText(configPath, "jetstream { store_dir: '/old' }");

        var options = new NatsOptions
        {
            ConfigFile = configPath,
            JetStream = new JetStreamOptions
            {
                StoreDir = "/old",
                MaxMemoryStore = 1_024 * 1_024,
                MaxFileStore = 10 * 1_024 * 1_024,
            },
        };

        var server = new NatsServer(options, NullLoggerFactory.Instance);
        return Task.FromResult(new ConfigReloadFixture(configPath, server));
    }

    public Task ReloadAsync(string configText)
    {
        File.WriteAllText(_configPath, configText);
        _server.ReloadConfigOrThrow();
        return Task.CompletedTask;
    }

    public ValueTask DisposeAsync()
    {
        _server.Dispose();
        if (File.Exists(_configPath))
            File.Delete(_configPath);

        return ValueTask.CompletedTask;
    }
}
