using ZB.MOM.WW.ScadaBridge.Commons.Entities.Audit; using ZB.MOM.WW.ScadaBridge.Commons.Types; using ZB.MOM.WW.ScadaBridge.Commons.Types.Audit; namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories; /// /// Operational-state data access for the central SiteCalls table. /// One row per /// ; sites remain the source of truth and this /// table is an eventually-consistent mirror fed by best-effort gRPC telemetry /// plus periodic reconciliation pulls. /// /// /// /// Unlike the partitioned append-only AuditLog, this table holds /// mutable operational state. is insert-if-not-exists /// then monotonic update — a status update with rank less than or equal to the /// stored status is a silent no-op so out-of-order telemetry, duplicate gRPC /// packets, and reconciliation pulls can all feed the same writer without /// rolling state backward. /// /// /// Status rank for monotonic comparison (lower wins): Submitted=0, /// Forwarded=1, Attempted=2, Skipped=2, Delivered=3, Failed=3, Parked=3, /// Discarded=3. Terminal statuses share rank 3 and are mutually exclusive /// — an attempt to upsert e.g. Delivered over an existing Parked /// row is a no-op. /// /// public interface ISiteCallAuditRepository { /// /// Inserts if no row with the same /// exists; otherwise updates the /// existing row IF AND ONLY IF the incoming status' rank strictly exceeds /// the stored status' rank. Out-of-order / duplicate updates are silently /// dropped (monotonic forward-only progression). /// /// The site call row to insert or monotonically update. /// Cancellation token. /// A task that represents the asynchronous operation. Task UpsertAsync(SiteCall siteCall, CancellationToken ct = default); /// /// Returns the row for the given id, or null if none exists. /// /// The tracked operation id to look up. /// Cancellation token. /// A task that resolves to the matching , or null if no row exists. Task GetAsync(TrackedOperationId id, CancellationToken ct = default); /// /// Returns up to rows matching /// , ordered by (CreatedAtUtc DESC, /// TrackedOperationId DESC). Use keyset paging via /// + /// to fetch subsequent pages. /// /// Filter criteria for the query. /// Keyset paging parameters. /// Cancellation token. /// A task that resolves to a page of rows matching the filter, ordered by creation time descending. Task> QueryAsync( SiteCallQueryFilter filter, SiteCallPaging paging, CancellationToken ct = default); /// /// Deletes terminal rows whose is /// strictly older than . Non-terminal rows /// (TerminalAtUtc IS NULL) are NEVER purged. Returns the number of rows /// deleted. /// /// UTC cutoff; terminal rows older than this are deleted. /// Cancellation token. /// A task that resolves to the number of rows deleted. Task PurgeTerminalAsync(DateTime olderThanUtc, CancellationToken ct = default); /// /// Computes a point-in-time global from the /// SiteCalls table. Counts are aggregated server-side (no row /// materialisation): StuckCount uses ; /// FailedLastInterval / DeliveredLastInterval use /// ; the current time for OldestPendingAge /// is captured inside the method. /// /// UTC threshold for classifying a row as stuck. /// UTC start of the delivered/failed interval window. /// Cancellation token. /// A task that resolves to a global computed from the current table state. Task ComputeKpisAsync( DateTime stuckCutoff, DateTime intervalSince, CancellationToken ct = default); /// /// Computes a point-in-time per source /// site. Sites with no SiteCalls rows at all are omitted. The stuck /// cutoff and interval bounds are interpreted as in . /// /// UTC threshold for classifying a row as stuck. /// UTC start of the delivered/failed interval window. /// Cancellation token. /// A task that resolves to a per-site KPI list; sites with no rows are omitted. Task> ComputePerSiteKpisAsync( DateTime stuckCutoff, DateTime intervalSince, CancellationToken ct = default); /// /// Computes a point-in-time per originating /// node. Nodes with no SiteCalls rows at all are omitted; rows with a /// NULL SourceNode are excluded. The stuck cutoff and interval /// bounds are interpreted as in . /// /// UTC threshold for classifying a row as stuck. /// UTC start of the delivered/failed interval window. /// Cancellation token. /// A task that resolves to a per-node KPI list; nodes with no rows are omitted. Task> ComputePerNodeKpisAsync( DateTime stuckCutoff, DateTime intervalSince, CancellationToken ct = default); }