// Tests for ConfigReloader.ApplyLoggingChanges.
// Go reference: golang/nats-server/server/reload.go — traceOption.Apply, debugOption.Apply.

using NATS.Server;
using NATS.Server.Configuration;
using Shouldly;

namespace NATS.Server.Core.Tests.Configuration;

public class LoggingReloadTests
{
    // ─── helpers ────────────────────────────────────────────────────

    private static NatsOptions BaseOpts() => new NatsOptions();

    // ─── tests ──────────────────────────────────────────────────────

    [Fact]
    public void No_changes_returns_no_changes()
    {
        // Go reference: reload.go traceOption.Apply — no-op when flags unchanged
        var old = BaseOpts();
        var updated = BaseOpts();

        var result = ConfigReloader.ApplyLoggingChanges(old, updated);

        result.HasChanges.ShouldBeFalse();
        result.LevelChanged.ShouldBeFalse();
        result.TraceChanged.ShouldBeFalse();
        result.DebugChanged.ShouldBeFalse();
    }

    [Fact]
    public void Level_changed_detected()
    {
        // Go reference: reload.go debugOption.Apply — enabling debug changes effective level
        var old = BaseOpts();           // Debug=false, Trace=false → "Information"
        var updated = BaseOpts();
        updated.Debug = true;           // Debug=true → "Debug"

        var result = ConfigReloader.ApplyLoggingChanges(old, updated);

        result.HasChanges.ShouldBeTrue();
        result.LevelChanged.ShouldBeTrue();
    }

    [Fact]
    public void Trace_enabled_detected()
    {
        // Go reference: reload.go traceOption.Apply — enabling trace flag
        var old = BaseOpts();
        var updated = BaseOpts();
        updated.Trace = true;

        var result = ConfigReloader.ApplyLoggingChanges(old, updated);

        result.HasChanges.ShouldBeTrue();
        result.TraceChanged.ShouldBeTrue();
    }

    [Fact]
    public void Trace_disabled_detected()
    {
        // Go reference: reload.go traceOption.Apply — disabling trace flag
        var old = BaseOpts();
        old.Trace = true;
        var updated = BaseOpts();       // Trace=false

        var result = ConfigReloader.ApplyLoggingChanges(old, updated);

        result.HasChanges.ShouldBeTrue();
        result.TraceChanged.ShouldBeTrue();
    }

    [Fact]
    public void Debug_enabled_detected()
    {
        // Go reference: reload.go debugOption.Apply — enabling debug flag
        var old = BaseOpts();
        var updated = BaseOpts();
        updated.Debug = true;

        var result = ConfigReloader.ApplyLoggingChanges(old, updated);

        result.HasChanges.ShouldBeTrue();
        result.DebugChanged.ShouldBeTrue();
    }

    [Fact]
    public void Debug_disabled_detected()
    {
        // Go reference: reload.go debugOption.Apply — disabling debug flag
        var old = BaseOpts();
        old.Debug = true;
        var updated = BaseOpts();       // Debug=false

        var result = ConfigReloader.ApplyLoggingChanges(old, updated);

        result.HasChanges.ShouldBeTrue();
        result.DebugChanged.ShouldBeTrue();
    }

    [Fact]
    public void OldLevel_and_NewLevel_set()
    {
        // Go reference: reload.go — level transition is reported with explicit before/after values
        var old = BaseOpts();           // Information
        var updated = BaseOpts();
        updated.Trace = true;           // Trace takes precedence

        var result = ConfigReloader.ApplyLoggingChanges(old, updated);

        result.LevelChanged.ShouldBeTrue();
        result.OldLevel.ShouldBe("Information");
        result.NewLevel.ShouldBe("Trace");
    }

    [Fact]
    public void Case_insensitive_level_comparison()
    {
        // Same effective level produced regardless of flag combination that yields the same tier
        // Debug=true on both sides → "Debug" == "Debug", no level change
        var old = BaseOpts();
        old.Debug = true;
        var updated = BaseOpts();
        updated.Debug = true;

        var result = ConfigReloader.ApplyLoggingChanges(old, updated);

        result.LevelChanged.ShouldBeFalse();
        result.HasChanges.ShouldBeFalse();
    }

    [Fact]
    public void Null_level_defaults_to_Information()
    {
        // Go reference: reload.go — absent log level is treated as Information
        // When neither Debug nor Trace is set the effective level is "Information"
        var old = BaseOpts();
        var updated = BaseOpts();

        var result = ConfigReloader.ApplyLoggingChanges(old, updated);

        // No change, and effective level should be "Information" for both sides
        result.LevelChanged.ShouldBeFalse();
        result.OldLevel.ShouldBeNull();  // only populated when a level change is detected
        result.NewLevel.ShouldBeNull();
    }

    [Fact]
    public void Multiple_changes_detected()
    {
        // Go reference: reload.go — independent trace and debug options both apply
        var old = BaseOpts();
        old.Debug = true;

        var updated = BaseOpts();
        updated.Trace = true;       // Debug removed, Trace added — both flags changed

        var result = ConfigReloader.ApplyLoggingChanges(old, updated);

        result.HasChanges.ShouldBeTrue();
        result.TraceChanged.ShouldBeTrue();
        result.DebugChanged.ShouldBeTrue();
        result.LevelChanged.ShouldBeTrue();
        result.OldLevel.ShouldBe("Debug");
        result.NewLevel.ShouldBe("Trace");
    }
}
