using Akka.Actor;
using Akka.Cluster.Tools.PublishSubscribe;
using Akka.Event;
using Microsoft.AspNetCore.SignalR;
using ZB.MOM.WW.OtOpcUa.Commons.Messages.Fleet;

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

/// <summary>
/// Akka actor that subscribes to the <c>fleet-status</c> DistributedPubSub topic and forwards
/// every <see cref="FleetStatusChanged"/> snapshot to all SignalR clients connected to
/// <see cref="FleetStatusHub"/>. Spawned on admin-role nodes by
/// <c>AddOtOpcUaSignalRBridges</c>.
///
/// The bridge runs locally on each admin node — every node that hosts the hub also forwards
/// snapshots to its own connected clients. That keeps the hub-to-actor wiring simple (no
/// cluster-singleton coordination needed) at the cost of duplicated DPS subscriptions on
/// multi-admin deployments. Acceptable since the messages are small + the SignalR fan-out
/// is per-node anyway.
/// </summary>
public sealed class FleetStatusSignalRBridge : ReceiveActor
{
    public const string TopicName = "fleet-status";

    private readonly IHubContext<FleetStatusHub> _hub;
    private readonly ILoggingAdapter _log = Context.GetLogger();

    /// <summary>Creates actor props for a FleetStatusSignalRBridge with the specified hub context.</summary>
    /// <param name="hub">The SignalR hub context.</param>
    /// <returns>Props for creating a new FleetStatusSignalRBridge actor.</returns>
    public static Props Props(IHubContext<FleetStatusHub> hub) =>
        Akka.Actor.Props.Create(() => new FleetStatusSignalRBridge(hub));

    /// <summary>Initializes a new instance of the FleetStatusSignalRBridge class.</summary>
    /// <param name="hub">The SignalR hub context for sending messages to clients.</param>
    public FleetStatusSignalRBridge(IHubContext<FleetStatusHub> hub)
    {
        _hub = hub;
        ReceiveAsync<FleetStatusChanged>(ForwardAsync);
        Receive<SubscribeAck>(_ => { /* DPS confirmation */ });
    }

    /// <inheritdoc />
    protected override void PreStart() =>
        DistributedPubSub.Get(Context.System).Mediator.Tell(new Subscribe(TopicName, Self));

    private async Task ForwardAsync(FleetStatusChanged msg)
    {
        try
        {
            await _hub.Clients.All.SendAsync(FleetStatusHub.MethodName, msg);
        }
        catch (Exception ex)
        {
            _log.Warning(ex, "FleetStatusSignalRBridge: SignalR push failed (count={Count})", msg.Nodes.Count);
        }
    }
}
