using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.AdminUI.Hubs;

namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests;

/// <summary>
///     Covers the in-process fan-out the Blazor Server Alerts / Script log pages rely on:
///     <see cref="IInProcessBroadcaster{T}.Publish"/> raises <c>Received</c> for every current
///     subscriber, and unsubscribing stops delivery. These pages read this broadcaster directly
///     instead of opening a self-targeted SignalR connection (unreachable behind a reverse proxy).
/// </summary>
public sealed class InProcessBroadcasterTests
{
    [Fact]
    public void Publish_raises_Received_for_all_current_subscribers()
    {
        var broadcaster = new InProcessBroadcaster<string>();
        var a = new List<string>();
        var b = new List<string>();
        broadcaster.Received += a.Add;
        broadcaster.Received += b.Add;

        broadcaster.Publish("evt-1");

        a.ShouldBe(["evt-1"]);
        b.ShouldBe(["evt-1"]);
    }

    [Fact]
    public void Unsubscribed_handler_stops_receiving()
    {
        var broadcaster = new InProcessBroadcaster<string>();
        var received = new List<string>();
        void Handler(string s) => received.Add(s);

        broadcaster.Received += Handler;
        broadcaster.Publish("first");
        broadcaster.Received -= Handler;
        broadcaster.Publish("second");

        received.ShouldBe(["first"]);
    }

    [Fact]
    public void Publish_with_no_subscribers_does_not_throw()
    {
        var broadcaster = new InProcessBroadcaster<int>();
        Should.NotThrow(() => broadcaster.Publish(42));
    }

    [Fact]
    public void New_broadcaster_is_not_connected()
    {
        var broadcaster = new InProcessBroadcaster<string>();

        broadcaster.IsConnected.ShouldBeFalse();
    }

    [Fact]
    public void SetConnected_true_flips_state_and_raises_once()
    {
        var broadcaster = new InProcessBroadcaster<string>();
        var raised = new List<bool>();
        broadcaster.ConnectionStateChanged += raised.Add;

        broadcaster.SetConnected(true);

        broadcaster.IsConnected.ShouldBeTrue();
        raised.ShouldBe([true]);
    }

    [Fact]
    public void SetConnected_same_value_does_not_raise()
    {
        var broadcaster = new InProcessBroadcaster<string>();
        var raised = new List<bool>();
        broadcaster.ConnectionStateChanged += raised.Add;

        broadcaster.SetConnected(true);
        broadcaster.SetConnected(true);

        raised.ShouldBe([true]);
    }

    [Fact]
    public void SetConnected_false_after_true_raises_false()
    {
        var broadcaster = new InProcessBroadcaster<string>();
        var raised = new List<bool>();
        broadcaster.ConnectionStateChanged += raised.Add;

        broadcaster.SetConnected(true);
        broadcaster.SetConnected(false);

        broadcaster.IsConnected.ShouldBeFalse();
        raised[^1].ShouldBeFalse();
    }
}
