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

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

/// <summary>
/// Akka actor that subscribes to the <c>script-logs</c> DistributedPubSub topic and forwards each
/// <see cref="ScriptLogEntry"/> to every SignalR client connected to <see cref="ScriptLogHub"/>.
/// </summary>
public sealed class ScriptLogSignalRBridge : ReceiveActor
{
    public const string TopicName = "script-logs";

    private readonly IHubContext<ScriptLogHub> _hub;
    private readonly IInProcessBroadcaster<ScriptLogEntry> _broadcaster;
    private readonly ILoggingAdapter _log = Context.GetLogger();

    /// <summary>Creates a Props instance for the ScriptLogSignalRBridge.</summary>
    /// <param name="hub">The SignalR hub context for sending messages to clients.</param>
    /// <param name="broadcaster">In-process fan-out read directly by the Blazor Server Script log page.</param>
    /// <returns>A configured <see cref="Akka.Actor.Props"/> for creating the actor.</returns>
    public static Props Props(IHubContext<ScriptLogHub> hub, IInProcessBroadcaster<ScriptLogEntry> broadcaster) =>
        Akka.Actor.Props.Create(() => new ScriptLogSignalRBridge(hub, broadcaster));

    /// <summary>Initializes a new instance of the <see cref="ScriptLogSignalRBridge"/> class.</summary>
    /// <param name="hub">The SignalR hub context for sending messages to clients.</param>
    /// <param name="broadcaster">In-process fan-out read directly by the Blazor Server Script log page.</param>
    public ScriptLogSignalRBridge(IHubContext<ScriptLogHub> hub, IInProcessBroadcaster<ScriptLogEntry> broadcaster)
    {
        _hub = hub;
        _broadcaster = broadcaster;
        ReceiveAsync<ScriptLogEntry>(ForwardAsync);
        // DPS subscription is now live — mark the feed connected so the Blazor "live" pill lights up.
        Receive<SubscribeAck>(_ => _broadcaster.SetConnected(true));
    }

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

    /// <inheritdoc />
    protected override void PostStop()
    {
        // Bridge stopping — the feed is no longer live, drop the "live" pill.
        _broadcaster.SetConnected(false);
        base.PostStop();
    }

    private async Task ForwardAsync(ScriptLogEntry msg)
    {
        // In-process fan-out first — this is what the Blazor Server Script log page reads. The hub
        // push is kept for any out-of-process (e.g. WASM) SignalR client.
        _broadcaster.Publish(msg);
        try
        {
            await _hub.Clients.All.SendAsync(ScriptLogHub.MethodName, msg);
        }
        catch (Exception ex)
        {
            _log.Warning(ex, "ScriptLogSignalRBridge: SignalR push failed for {ScriptId}", msg.ScriptId);
        }
    }
}
