using ZB.MOM.WW.MxGateway.Contracts.Proto;

namespace ZB.MOM.WW.MxGateway.Server.Alarms;

/// <summary>Lifecycle state of the gateway's central alarm monitor.</summary>
public enum GatewayAlarmMonitorState
{
    /// <summary>Alarm monitoring is switched off (<c>MxGateway:Alarms:Enabled</c> is false).</summary>
    Disabled,

    /// <summary>The monitor is opening or re-opening its worker session.</summary>
    Starting,

    /// <summary>The monitor is connected and tracking the active-alarm set.</summary>
    Monitoring,

    /// <summary>The monitor's last lifecycle attempt failed; a restart is pending.</summary>
    Faulted,
}

/// <summary>
///     The gateway's always-on alarm broker. A single gateway-owned worker
///     session monitors the AVEVA alarm provider; this service caches the
///     current active-alarm set and fans it out to any number of clients —
///     no client needs to open its own worker session to see alarms.
/// </summary>
public interface IGatewayAlarmService
{
    /// <summary>Current monitor lifecycle state.</summary>
    GatewayAlarmMonitorState State { get; }

    /// <summary>Diagnostic message from the most recent fault, or null.</summary>
    string? LastError { get; }

    /// <summary>Process id of the worker backing the monitor, when one is attached.</summary>
    int? WorkerProcessId { get; }

    /// <summary>A point-in-time copy of the current active-alarm set.</summary>
    IReadOnlyList<ActiveAlarmSnapshot> CurrentAlarms { get; }

    /// <summary>
    ///     Attaches to the central alarm feed. The returned stream yields one
    ///     <see cref="AlarmFeedMessage"/> per currently-active alarm, then a
    ///     single <c>snapshot_complete</c> sentinel, then a <c>transition</c>
    ///     for every subsequent change.
    /// </summary>
    /// <param name="alarmFilterPrefix">Optional alarm-reference prefix scoping the feed.</param>
    /// <param name="cancellationToken">Token that ends the subscription.</param>
    IAsyncEnumerable<AlarmFeedMessage> StreamAsync(
        string? alarmFilterPrefix,
        CancellationToken cancellationToken);

    /// <summary>
    ///     Acknowledges an alarm through the monitor's worker session. Never
    ///     throws — transport and monitor-state failures surface in the
    ///     reply's <see cref="AcknowledgeAlarmReply.ProtocolStatus"/>.
    /// </summary>
    /// <param name="request">The acknowledge request.</param>
    /// <param name="cancellationToken">Token to cancel the call.</param>
    Task<AcknowledgeAlarmReply> AcknowledgeAsync(
        AcknowledgeAlarmRequest request,
        CancellationToken cancellationToken);
}
