using Microsoft.AspNetCore.SignalR;
using ZB.MOM.WW.MxGateway.Contracts.Proto;

namespace ZB.MOM.WW.MxGateway.Server.Dashboard.Hubs;

/// <summary>
/// Broadcasts MxEvents to <see cref="EventsHub"/> clients subscribed to the
/// session's group. Fire-and-forget: we hand the send to the hub context
/// and return immediately so the source gRPC stream is never blocked.
/// Errors are logged once and dropped — keeping the SignalR mirror best-effort
/// preserves the gRPC contract that exists today.
/// </summary>
public sealed class DashboardEventBroadcaster(
    IHubContext<EventsHub> hubContext,
    ILogger<DashboardEventBroadcaster> logger) : IDashboardEventBroadcaster
{
    /// <summary>Publishes an MX event to connected dashboard clients.</summary>
    /// <param name="sessionId">The session identifier.</param>
    /// <param name="mxEvent">The MX event to publish.</param>
    public void Publish(string sessionId, MxEvent mxEvent)
    {
        if (string.IsNullOrEmpty(sessionId) || mxEvent is null)
        {
            return;
        }

        // Wrap the Task acquisition in a try/catch so a hypothetical synchronous throw
        // from SendAsync (e.g. an implementation that throws before returning the Task)
        // cannot escape Publish. The interface contract is never-throw; fire-and-forget.
        Task send;
        try
        {
            send = hubContext.Clients
                .Group(EventsHub.GroupName(sessionId))
                .SendAsync(EventsHub.EventMessage, mxEvent);
        }
        catch (Exception ex)
        {
            logger.LogDebug(ex, "Dashboard event mirror to session {SessionId} threw synchronously.", sessionId);
            return;
        }

        if (!send.IsCompletedSuccessfully)
        {
            _ = send.ContinueWith(
                t =>
                {
                    if (t.Exception is { } ex)
                    {
                        logger.LogDebug(ex, "Dashboard event mirror to session {SessionId} failed.", sessionId);
                    }
                },
                TaskScheduler.Default);
        }
    }
}
