using ZB.MOM.WW.ScadaBridge.AuditLog.Payload;

namespace ZB.MOM.WW.ScadaBridge.AuditLog.Central;

/// <summary>
/// Read-side surface exposing the central-side
/// audit-health counters: <see cref="CentralAuditWriteFailures"/> (every
/// repository insert throw from <see cref="CentralAuditWriter"/> /
/// <see cref="AuditLogIngestActor"/>), <see cref="AuditRedactionFailure"/>
/// (every payload-filter redactor throw on the central path), and
/// <see cref="SiteAuditTelemetryStalled"/> (per-site latched state from the
/// <see cref="SiteAuditTelemetryStalledTracker"/>).
/// </summary>
/// <remarks>
/// <para>
/// <b>Read-only contract.</b> Implementations expose a point-in-time snapshot
/// — increments and tracker updates happen through the dedicated counter /
/// tracker interfaces, not through this surface. Consumers (central
/// health pages) read these properties; they never mutate.
/// </para>
/// <para>
/// <b>Why a parallel surface from <see cref="ICentralHealthAggregator"/>.</b>
/// <see cref="ICentralHealthAggregator"/> aggregates per-site
/// <c>SiteHealthState</c> reports the SITE emits. The central audit-write
/// failure / redaction-failure counters originate ON central (no site report
/// carries them), so they live on a dedicated snapshot rather than being
/// retro-fitted into a per-site state. The two surfaces will be composed at
/// the dashboard layer.
/// </para>
/// </remarks>
public interface IAuditCentralHealthSnapshot
{
    /// <summary>
    /// Count of central-side audit-write failures since process start.
    /// Incremented by every <see cref="CentralAuditWriter"/> /
    /// <see cref="AuditLogIngestActor"/> repository insert that throws.
    /// </summary>
    int CentralAuditWriteFailures { get; }

    /// <summary>
    /// Count of central-side payload-filter redactor over-redactions since
    /// process start. Incremented by every header / body / SQL-parameter
    /// redactor stage that throws (the filter falls back to the
    /// <c>&lt;redacted: redactor error&gt;</c> marker and never aborts the
    /// user-facing action). Sites have their own counter
    /// (<see cref="IAuditRedactionFailureCounter"/>-backed
    /// <c>SiteHealthReport.AuditRedactionFailure</c>) and the central
    /// composition root's binding routes ALL central redactor throws
    /// (CentralAuditWriter + AuditLogIngestActor paths) into this counter.
    /// </summary>
    int AuditRedactionFailure { get; }

    /// <summary>
    /// Count of inbound request/response body truncations at the
    /// <see cref="ZB.MOM.WW.ScadaBridge.AuditLog.Configuration.AuditLogOptions.InboundMaxBytes"/>
    /// ceiling since process start. Incremented by
    /// <see cref="ZB.MOM.WW.ScadaBridge.InboundAPI.Middleware.AuditWriteMiddleware"/>
    /// whenever either the request or response body exceeds the cap and is
    /// truncated in the audit copy. A sustained non-zero count can indicate
    /// callers sending unexpectedly large bodies.
    /// </summary>
    int AuditInboundCeilingHits { get; }

    /// <summary>
    /// Count of AuditLog partition-purge failures since process start. Incremented by
    /// <see cref="AuditLogPurgeActor"/> every time a purge step throws — a partition
    /// switch-out, a per-channel override DELETE, or the pre-purge boundary enumeration.
    /// A sustained non-zero count means the retention job is silently not draining the
    /// table; each failure also publishes an <see cref="AuditLogPurgeFailedEvent"/> on the
    /// EventStream (arch-review 04, S2).
    /// </summary>
    int PurgeFailures { get; }

    /// <summary>
    /// Per-site latched stalled state: <c>true</c> when the
    /// <see cref="SiteAuditReconciliationActor"/> has observed two
    /// consecutive non-draining cycles for that site, <c>false</c> after the
    /// first draining cycle. Sites absent from the map are interpreted as
    /// healthy (<c>Stalled=false</c> default). Snapshot is a defensive
    /// copy — readers must not mutate.
    /// </summary>
    IReadOnlyDictionary<string, bool> SiteAuditTelemetryStalled { get; }
}
