// Copyright 2012-2025 The NATS Authors
// Licensed under the Apache License, Version 2.0
namespace ZB.MOM.NatsNet.Server.Tests.Config;

using System.Security.Authentication;
using ZB.MOM.NatsNet.Server.Config;
using Shouldly;
using Xunit;

public class ServerOptionsConfigurationTests
{
    [Fact]
    public void ProcessConfigString_MinimalJson_SetsPort()
    {
        var opts = ServerOptionsConfiguration.ProcessConfigString("""{"port": 4222}""");
        opts.Port.ShouldBe(4222);
    }

    [Fact]
    public void ProcessConfigString_EmptyJson_AppliesDefaults()
    {
        var opts = ServerOptionsConfiguration.ProcessConfigString("{}");
        opts.Port.ShouldBe(ServerConstants.DefaultPort);
        opts.Host.ShouldBe(ServerConstants.DefaultHost);
        opts.MaxPayload.ShouldBe(ServerConstants.MaxPayload);
    }

    [Fact]
    public void ProcessConfigString_AllBasicFields_Roundtrip()
    {
        var json = """
            {
              "port": 5222,
              "host": "127.0.0.1",
              "server_name": "test-server",
              "debug": true,
              "trace": true,
              "max_connections": 100,
              "auth_timeout": 2.0
            }
            """;
        var opts = ServerOptionsConfiguration.ProcessConfigString(json);
        opts.Port.ShouldBe(5222);
        opts.Host.ShouldBe("127.0.0.1");
        opts.ServerName.ShouldBe("test-server");
        opts.Debug.ShouldBeTrue();
        opts.Trace.ShouldBeTrue();
        opts.MaxConn.ShouldBe(100);
        opts.AuthTimeout.ShouldBe(2.0);
    }

    [Fact]
    public void ProcessConfigFile_FileNotFound_Throws()
    {
        Should.Throw<FileNotFoundException>(() =>
            ServerOptionsConfiguration.ProcessConfigFile("/nonexistent/path.json"));
    }

    [Fact]
    public void ProcessConfigFile_ValidFile_ReturnsOptions()
    {
        var tmpFile = Path.GetTempFileName();
        File.WriteAllText(tmpFile, """{"port": 9090, "server_name": "from-file"}""");
        try
        {
            var opts = ServerOptionsConfiguration.ProcessConfigFile(tmpFile);
            opts.Port.ShouldBe(9090);
            opts.ServerName.ShouldBe("from-file");
        }
        finally { File.Delete(tmpFile); }
    }
}

public class NatsDurationJsonConverterTests
{
    [Theory]
    [InlineData("2s",    0, 0, 2, 0)]
    [InlineData("100ms", 0, 0, 0, 100)]
    [InlineData("1h30m", 1, 30, 0, 0)]
    public void Parse_ValidDurationStrings_ReturnsCorrectTimeSpan(
        string input, int hours, int minutes, int seconds, int ms)
    {
        var expected = new TimeSpan(0, hours, minutes, seconds, ms);
        NatsDurationJsonConverter.Parse(input).ShouldBe(expected);
    }

    [Fact]
    public void Parse_FiveMinutesTenSeconds_ReturnsCorrectSpan()
    {
        var result = NatsDurationJsonConverter.Parse("5m10s");
        result.ShouldBe(TimeSpan.FromSeconds(310));
    }

    [Fact]
    public void Parse_InvalidString_ThrowsFormatException()
    {
        Should.Throw<FormatException>(() => NatsDurationJsonConverter.Parse("notaduration"));
    }
}

public class StorageSizeJsonConverterTests
{
    [Theory]
    [InlineData("1GB",  1L * 1024 * 1024 * 1024)]
    [InlineData("512MB", 512L * 1024 * 1024)]
    [InlineData("1KB",  1024L)]
    [InlineData("1024", 1024L)]
    public void Parse_ValidSizeStrings_ReturnsBytes(string input, long expectedBytes)
    {
        StorageSizeJsonConverter.Parse(input).ShouldBe(expectedBytes);
    }
}

public class NatsUrlJsonConverterTests
{
    [Theory]
    [InlineData("nats://localhost:4222", "nats://localhost:4222")]
    [InlineData("localhost:4222",        "nats://localhost:4222")]
    [InlineData("localhost",             "nats://localhost")]
    public void Normalise_ValidUrls_NormalisesCorrectly(string input, string expected)
    {
        NatsUrlJsonConverter.Normalise(input).ShouldBe(expected);
    }

    [Fact]
    public void Normalise_EmptyString_ReturnsEmpty()
    {
        NatsUrlJsonConverter.Normalise(string.Empty).ShouldBe(string.Empty);
    }
}

public class TlsVersionJsonConverterTests
{
    [Theory]
    [InlineData("1.2",   SslProtocols.Tls12)]
    [InlineData("TLS12", SslProtocols.Tls12)]
    [InlineData("1.3",   SslProtocols.Tls13)]
    [InlineData("TLS13", SslProtocols.Tls13)]
    public void Parse_ValidVersionStrings_ReturnsCorrectProtocol(string input, SslProtocols expected)
    {
        TlsVersionJsonConverter.Parse(input).ShouldBe(expected);
    }

    [Fact]
    public void Parse_InvalidVersion_ThrowsFormatException()
    {
        Should.Throw<FormatException>(() => TlsVersionJsonConverter.Parse("2.0"));
    }
}
