using DeepDrftPublic.Client.Services;

namespace DeepDrftTests;

/// <summary>
/// Unit tests for the Theater-Mode auto-exit invariant on <see cref="WaveformVisualizerControlState"/>
/// (Phase 20 bug fix): when both subsystems are disabled, <see cref="WaveformVisualizerControlState.CoerceTheaterMode"/>
/// must force <c>TheaterMode = false</c> so observers never see a stranded-theater state.
/// </summary>
[TestFixture]
public class WaveformVisualizerControlStateTests
{
    private WaveformVisualizerControlState _state = null!;

    [SetUp]
    public void SetUp() => _state = new WaveformVisualizerControlState();

    // ── CoerceTheaterMode guard ──

    // Both off + Theater on → coerce exits theater.
    [Test]
    public void CoerceTheaterMode_BothOff_TheaterBecomesFalse()
    {
        _state.TheaterMode = true;
        _state.LavaEnabled = false;
        _state.WaveformEnabled = false;

        _state.CoerceTheaterMode();

        Assert.That(_state.TheaterMode, Is.False);
    }

    // Lava still on → theater is left alone even if waveform is off.
    [Test]
    public void CoerceTheaterMode_LavaOnWaveformOff_TheaterPreserved()
    {
        _state.TheaterMode = true;
        _state.LavaEnabled = true;
        _state.WaveformEnabled = false;

        _state.CoerceTheaterMode();

        Assert.That(_state.TheaterMode, Is.True);
    }

    // Waveform still on → theater is left alone even if lava is off.
    [Test]
    public void CoerceTheaterMode_WaveformOnLavaOff_TheaterPreserved()
    {
        _state.TheaterMode = true;
        _state.LavaEnabled = false;
        _state.WaveformEnabled = true;

        _state.CoerceTheaterMode();

        Assert.That(_state.TheaterMode, Is.True);
    }

    // Theater already false + both off → no change (no false-positive write).
    [Test]
    public void CoerceTheaterMode_TheaterAlreadyFalse_NoChange()
    {
        _state.TheaterMode = false;
        _state.LavaEnabled = false;
        _state.WaveformEnabled = false;

        _state.CoerceTheaterMode();

        Assert.That(_state.TheaterMode, Is.False);
    }

    // ── Changed event fires once with coerced state visible ──

    // Verify that after coercion, the Changed notification carries the already-corrected TheaterMode
    // value — all observers see a consistent state in the single Changed cycle.
    [Test]
    public void NotifyChanged_AfterCoerce_ObserverSeesTheaterFalse()
    {
        _state.TheaterMode = true;
        _state.LavaEnabled = false;
        _state.WaveformEnabled = false;

        bool? observedTheaterMode = null;
        _state.Changed += () => observedTheaterMode = _state.TheaterMode;

        _state.CoerceTheaterMode();
        _state.NotifyChanged();

        Assert.That(observedTheaterMode, Is.False);
    }
}
