using ZB.MOM.WW.ScadaBridge.Commons.Entities.Notifications;
using ZB.MOM.WW.ScadaBridge.Commons.Types.Notifications;
namespace ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Repositories;
///
/// Data access for the central notification outbox — the queue of
/// rows the outbox actor drains, retries, and audits. Distinct from
/// , which manages notification list configuration.
///
///
/// Persistence model: and commit
/// internally, so each call is its own transaction — suited to the outbox actor committing one
/// row's status transition at a time. The standalone is available
/// for callers that stage multiple changes and want to flush them together.
///
public interface INotificationOutboxRepository
{
///
/// Inserts only if no row with the same
/// exists. Returns true when a new
/// row was inserted, false when an existing row was left untouched.
/// Commits internally — this call is its own transaction.
///
/// The notification to insert.
/// Cancellation token.
/// True if inserted, false if already exists.
Task InsertIfNotExistsAsync(Notification n, CancellationToken cancellationToken = default);
///
/// Returns notifications ready for a delivery attempt: Pending rows, plus
/// Retrying rows whose NextAttemptAt is at or before .
/// Terminal rows are excluded. Ordered by CreatedAt ascending, capped at
/// .
///
/// The current time for evaluating due retries.
/// Maximum number of rows to return.
/// Cancellation token.
/// A list of notifications ready for delivery.
Task> GetDueAsync(DateTimeOffset now, int batchSize, CancellationToken cancellationToken = default);
/// Returns the notification with the given id, or null.
/// The notification identifier.
/// Cancellation token.
/// The notification, or null if not found.
Task GetByIdAsync(string notificationId, CancellationToken cancellationToken = default);
///
/// Persists 's delivery-state columns —
/// Status, RetryCount, LastError, ResolvedTargets,
/// LastAttemptAt, NextAttemptAt, DeliveredAt. Commits
/// internally — this call is its own transaction.
///
///
/// Scope is deliberately narrow. Those seven columns are the ONLY
/// mutable state a notification has: everything else (identity, type, list,
/// subject, body, type data, source/origin attribution, enqueue and creation
/// timestamps) is written once at ingest and is immutable by contract. Every
/// caller — the dispatcher's per-attempt write and the operator retry/discard
/// one-shots — touches only this set. Implementations are therefore free to
/// issue a targeted UPDATE of these columns rather than rewriting the whole
/// row, which matters because the row carries nvarchar(max) body and
/// payload columns and the dispatcher writes on EVERY attempt. A future
/// caller that needs to change an immutable column must add its own method
/// rather than widening this one.
///
/// The return value is the not-found signal. A targeted UPDATE against
/// a row that no longer exists (the retention purge removed it between the
/// read and the write) affects zero rows and is otherwise indistinguishable
/// from success — which is how an operator Retry/Discard came to report
/// success against a vanished notification. Implementations MUST return
/// when no row matched. Callers that speak to a human
/// (the operator one-shots) must surface that as "not found"; the dispatcher
/// treats it as a lost race and logs.
///
///
/// The notification whose delivery state should be persisted.
/// Cancellation token.
///
/// when the row was found and its delivery state
/// persisted; when no row with that
/// NotificationId exists any more.
///
Task UpdateAsync(Notification n, CancellationToken cancellationToken = default);
///
/// Returns a page of notifications matching , ordered by
/// CreatedAt descending, together with the total matching count.
///
/// The query filter.
/// The page number (1-based).
/// The page size.
/// Cancellation token.
/// A tuple of rows and total count.
Task<(IReadOnlyList Rows, int TotalCount)> QueryAsync(
NotificationOutboxFilter filter, int pageNumber, int pageSize, CancellationToken cancellationToken = default);
///
/// Bulk-deletes terminal rows (Delivered/Parked/Discarded) whose CreatedAt is
/// older than . Returns the number of rows deleted.
///
/// The cutoff time for deletion.
/// Cancellation token.
/// The number of rows deleted.
Task DeleteTerminalOlderThanAsync(DateTimeOffset cutoff, CancellationToken cancellationToken = default);
///
/// Computes a point-in-time . The stuck and
/// delivered cutoffs are supplied by the caller; the current time used for
/// OldestPendingAge is captured inside the method.
///
/// The time threshold for marking notifications as stuck.
/// The time threshold for counting delivered notifications.
/// Cancellation token.
/// A KPI snapshot.
Task ComputeKpisAsync(
DateTimeOffset stuckCutoff, DateTimeOffset deliveredSince, CancellationToken cancellationToken = default);
///
/// Computes a point-in-time per source site.
/// Sites with no notification rows at all are omitted. The stuck and delivered cutoffs
/// are supplied by the caller; the current time used for OldestPendingAge is
/// captured inside the method.
///
/// The time threshold for marking notifications as stuck.
/// The time threshold for counting delivered notifications.
/// Cancellation token.
/// A list of per-site KPI snapshots.
Task> ComputePerSiteKpisAsync(
DateTimeOffset stuckCutoff, DateTimeOffset deliveredSince, CancellationToken cancellationToken = default);
///
/// Computes a point-in-time per originating node.
/// Nodes with no notification rows at all are omitted; rows with a NULL
/// SourceNode are excluded. The stuck and delivered cutoffs are supplied by the
/// caller; the current time used for OldestPendingAge is captured inside the method.
///
/// The time threshold for marking notifications as stuck.
/// The time threshold for counting delivered notifications.
/// Cancellation token.
/// A list of per-node KPI snapshots, ordered by node name.
Task> ComputePerNodeKpisAsync(
DateTimeOffset stuckCutoff, DateTimeOffset deliveredSince, CancellationToken cancellationToken = default);
///
/// Persists pending changes tracked on the underlying context. Use this when staging
/// multiple changes for a single commit; the individual mutating methods on this
/// interface already commit on their own.
///
/// Cancellation token.
/// The number of changes persisted.
Task SaveChangesAsync(CancellationToken cancellationToken = default);
}