using Shouldly;
using Xunit;
using ZB.MOM.WW.OtOpcUa.AdminUI.Hubs;
using ZB.MOM.WW.OtOpcUa.Commons.Messages.Drivers;

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

/// <summary>
///     Covers the in-process push contract the Blazor Server <c>DriverStatusPanel</c> relies on:
///     <see cref="IDriverStatusSnapshotStore.SnapshotChanged"/> fires on every
///     <see cref="IDriverStatusSnapshotStore.Upsert"/>, and <c>TryGet</c> returns the latest.
///     The panel subscribes to this store directly instead of opening a self-targeted SignalR
///     connection (which a server-side component can't reach behind a reverse proxy).
/// </summary>
public sealed class DriverStatusSnapshotStoreTests
{
    private static DriverHealthChanged Snap(string instance, string state = "Healthy") =>
        new("MAIN", instance, state, null, null, 0, new DateTime(2026, 5, 29, 0, 0, 0, DateTimeKind.Utc));

    [Fact]
    public void Upsert_raises_SnapshotChanged_with_the_stored_snapshot()
    {
        var store = new InMemoryDriverStatusSnapshotStore();
        var received = new List<DriverHealthChanged>();
        store.SnapshotChanged += received.Add;

        var snap = Snap("drv-1", "Faulted");
        store.Upsert(snap);

        received.Count.ShouldBe(1);
        received[0].ShouldBeSameAs(snap);
    }

    [Fact]
    public void Upsert_then_TryGet_returns_the_latest_snapshot()
    {
        var store = new InMemoryDriverStatusSnapshotStore();
        store.Upsert(Snap("drv-1", "Healthy"));
        store.Upsert(Snap("drv-1", "Degraded"));

        store.TryGet("drv-1", out var latest).ShouldBeTrue();
        latest.State.ShouldBe("Degraded");
    }

    [Fact]
    public void Unsubscribed_handler_stops_receiving_after_removal()
    {
        var store = new InMemoryDriverStatusSnapshotStore();
        var count = 0;
        void Handler(DriverHealthChanged _) => count++;

        store.SnapshotChanged += Handler;
        store.Upsert(Snap("drv-1"));
        store.SnapshotChanged -= Handler;
        store.Upsert(Snap("drv-1"));

        count.ShouldBe(1);
    }
}
