using Microsoft.Extensions.Logging;

namespace ZB.MOM.WW.ScadaBridge.DeploymentManager;

/// <summary>
/// Default <see cref="IDeploymentStatusNotifier"/> implementation. A simple
/// in-process event broadcaster: registered as a DI singleton so it is shared
/// between the central-process <see cref="DeploymentService"/> and the Central
/// UI's Blazor circuits.
///
/// A throwing subscriber must never break the deployment pipeline, so each
/// handler is invoked individually and its exceptions are caught and logged.
/// </summary>
public sealed class DeploymentStatusNotifier : IDeploymentStatusNotifier
{
    private readonly ILogger<DeploymentStatusNotifier> _logger;

    /// <summary>Initializes a new instance of <see cref="DeploymentStatusNotifier"/>.</summary>
    /// <param name="logger">Logger instance used when a subscriber throws.</param>
    public DeploymentStatusNotifier(ILogger<DeploymentStatusNotifier> logger)
    {
        _logger = logger;
    }

    /// <summary>Raised after each call to <see cref="NotifyStatusChanged"/> to broadcast a deployment status change to all registered subscribers.</summary>
    public event Action<DeploymentStatusChange>? StatusChanged;

    /// <inheritdoc />
    public void NotifyStatusChanged(DeploymentStatusChange change)
    {
        var handlers = StatusChanged;
        if (handlers == null)
            return;

        // Invoke each subscriber in isolation: one faulting handler (e.g. a
        // disposed Blazor circuit) must not stop the others from being notified
        // and must not propagate back into the deployment pipeline.
        foreach (var handler in handlers.GetInvocationList())
        {
            try
            {
                ((Action<DeploymentStatusChange>)handler)(change);
            }
            catch (Exception ex)
            {
                _logger.LogWarning(ex,
                    "A deployment-status-change subscriber threw for deployment {DeploymentId} " +
                    "(status {Status}); continuing with remaining subscribers",
                    change.DeploymentId, change.Status);
            }
        }
    }
}
