using ZB.MOM.WW.ScadaBridge.Commons.Messages.Integration;

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

/// <summary>
/// Mockable abstraction over the central-side <c>PullSiteCalls</c> gRPC client
/// surface used by the Site Call Audit reconciliation tick to fetch the
/// next batch of cached-call operational rows from a specific site — the
/// documented periodic self-heal pull that backfills the eventually-consistent
/// central <c>SiteCalls</c> mirror when best-effort push telemetry is lost.
/// Extracted so the (separate, follow-up) reconciliation actor can be
/// unit-tested against an in-memory stub without standing up a real
/// <c>GrpcChannel</c> per site.
/// </summary>
/// <remarks>
/// <para>
/// The home is <c>ZB.MOM.WW.ScadaBridge.AuditLog.Central</c> rather than the
/// <c>ZB.MOM.WW.ScadaBridge.SiteCallAudit</c> project so it can reuse the
/// <see cref="ISiteEnumerator"/> / <see cref="SiteEntry"/> endpoint-resolution
/// abstraction that already lives here (and that the sibling
/// <see cref="IPullAuditEventsClient"/> uses) — SiteCallAudit does not reference
/// AuditLog, so hosting the client there would mean duplicating the enumerator.
/// This mirrors the decision to keep <see cref="SiteCallDtoMapper"/> in
/// <c>ZB.MOM.WW.ScadaBridge.Communication</c>.
/// </para>
/// <para>
/// Implementations MUST NOT throw on transport faults the reconciliation tick
/// can tolerate (connection refused, deadline exceeded, cancellation) — one
/// offline site must never sink the rest of the tick. The
/// <see cref="PullSiteCallsResponse.SiteCalls"/> are returned oldest-first by
/// <c>UpdatedAtUtc</c> with the <c>SourceSite</c> re-stamped from the dialed
/// site id (the site leaves it empty, being unaware of its own id), and a
/// <c>MoreAvailable</c> flag the caller uses to decide whether to fire another
/// pull immediately.
/// </para>
/// </remarks>
public interface IPullSiteCallsClient
{
    /// <summary>
    /// Issues a <c>PullSiteCalls</c> RPC against the site whose gRPC endpoint is
    /// registered against <paramref name="siteId"/>. Returns the next batch of
    /// <see cref="ZB.MOM.WW.ScadaBridge.Commons.Entities.Audit.SiteCall"/> rows
    /// ordered oldest-first (with <c>SourceSite</c> re-stamped from
    /// <paramref name="siteId"/>) AND a <c>MoreAvailable</c> flag the caller uses
    /// to decide whether to fire another pull immediately.
    /// </summary>
    /// <param name="siteId">The identifier of the site to pull cached-call operational rows from.</param>
    /// <param name="sinceUtc">Only rows with an <c>UpdatedAtUtc</c> at or after this cursor time are returned.</param>
    /// <param name="afterId">
    /// The composite-keyset tiebreak cursor. When non-null it is the
    /// <c>TrackedOperationId</c> of the last row already consumed at
    /// <paramref name="sinceUtc"/>; the site returns only rows strictly greater
    /// than the composite <c>(UpdatedAtUtc, TrackedOperationId)</c> pair, so a
    /// burst sharing one exact <c>UpdatedAtUtc</c> drains via the id tiebreak
    /// instead of pinning the inclusive-timestamp cursor. Null on the first pull
    /// (or against a legacy site) preserves the inclusive <c>&gt;=</c> contract.
    /// </param>
    /// <param name="batchSize">Maximum number of rows to return per call.</param>
    /// <param name="ct">Cancellation token.</param>
    /// <returns>A task that resolves to the next reconciliation batch with a <c>MoreAvailable</c> flag.</returns>
    Task<PullSiteCallsResponse> PullAsync(
        string siteId,
        DateTime sinceUtc,
        string? afterId,
        int batchSize,
        CancellationToken ct);
}
