using ZB.MOM.WW.ScadaBridge.Commons.Messages.DebugView;
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Streaming;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Enums;
namespace ZB.MOM.WW.ScadaBridge.CentralUI.Services;
///
/// Read-only operator service that aggregates the current alarm picture across
/// all Enabled instances of a single site (Operator Alarm Summary).
///
///
///
/// There is no central alarm store. The summary is assembled at query time by
/// fanning out one request per Enabled instance
/// (via the injected , which delegates to
/// the existing single-shot
///
/// Ask) and flattening every snapshot's
/// into s. The fan-out is best-effort: an instance
/// whose snapshot fetch throws, times out, or reports
/// is recorded in
/// and never aborts the
/// whole call.
///
///
/// The page is read-only — there are no ack / shelve / write operations. All
/// filtering and roll-up math happens client-side from the returned rows.
///
///
public interface IAlarmSummaryService
{
///
/// Fetches and aggregates the current alarms across every Enabled instance of
/// the given site.
///
/// The site primary key.
/// Cancellation token.
///
/// An with one
/// per active/mirrored alarm condition plus the unique names of any instances
/// whose snapshot could not be obtained.
///
Task GetSiteAlarmsAsync(int siteId, CancellationToken cancellationToken = default);
///
/// Builds an directly from an in-memory live
/// snapshot (plan #10, Task 5) — the current alarms served by
///
/// — instead of fanning out per-instance snapshot Asks. Each
/// is flattened to one
/// (instance taken from
/// ) and ordered with the SAME
/// deterministic instance-then-alarm-name sort as
/// , so the two paths are interchangeable.
///
///
/// The live cache carries only alarm state, so it cannot know which Enabled
/// instances are silent-but-reporting versus not reporting at all;
/// is therefore always
/// empty on this path. The page keeps its periodic
/// poll as the authority for "not reporting" (and as a live-stream safety net).
///
/// The current live alarm snapshot for a site.
/// An whose is empty.
AlarmSummaryResult BuildFromLiveAlarms(IReadOnlyList alarms);
///
/// Pure roll-up over a set of s. Exposed so the
/// page (and tests) can recompute the headline tiles without re-querying.
///
/// The alarm rows to summarize.
/// The aggregated roll-up.
AlarmRollup ComputeRollup(IReadOnlyList rows);
}
/// The result of a site alarm-summary query.
/// One row per alarm condition reported across the site's Enabled instances.
///
/// Unique names of Enabled instances whose snapshot could not be obtained
/// (fetch threw, timed out, or returned ).
///
public sealed record AlarmSummaryResult(
IReadOnlyList Alarms,
IReadOnlyList NotReportingInstances);
///
/// One alarm condition paired with the instance it belongs to. The
/// carries everything the
/// AlarmStateBadges component needs to render.
///
/// Unique name of the owning instance.
/// The alarm condition (state / kind / severity / level / native sub-state).
public sealed record AlarmSummaryRow(
string InstanceUniqueName,
AlarmStateChanged Alarm);
///
/// Pure point-in-time roll-up over a set of s.
///
/// Count of rows whose is .
/// Highest among active rows; 0 when none active.
/// Active, unacknowledged native conditions (Kind != Computed).
/// Per- row counts (only kinds with at least one row appear).
public sealed record AlarmRollup(
int TotalActive,
int WorstSeverity,
int UnackedCount,
IReadOnlyDictionary CountsByKind);