using ZB.MOM.WW.ScadaBridge.Commons.Messages.Audit;
using ZB.MOM.WW.ScadaBridge.Commons.Messages.Notification;
using ZB.MOM.WW.ScadaBridge.Commons.Types;

namespace ZB.MOM.WW.ScadaBridge.CentralUI.Services;

/// <summary>
/// Process-level memoized point-in-time KPI snapshots shared by every Blazor circuit on
/// this node (arch-review WP2.4, finding #8 — the per-circuit polling half).
/// <para>
/// Every KPI here is a <em>global, point-in-time aggregate</em>: it does not vary by user,
/// site scope, or role, so N circuits asking for it inside one refresh window are asking
/// the identical question. Without memoization, ten Health dashboards meant ten Asks →
/// ten aggregate SQL round trips every ten seconds. Each accessor is independently
/// memoized with a short TTL and single-flight production, so the fleet costs ONE round
/// trip per KPI per window regardless of viewer count.
/// </para>
/// <para>
/// Faults are never memoized: a failed query is re-attempted by the next caller, and the
/// caller still sees the exception exactly as it would from a direct query — the pages'
/// existing per-tile "unavailable" degradation is unchanged.
/// </para>
/// </summary>
public interface IKpiSnapshotCache
{
    /// <summary>Global Notification Outbox KPIs (queue depth, stuck, parked, delivered-last-interval).</summary>
    /// <param name="forceRefresh">Bypass a still-fresh value (operator "Refresh"); an in-flight round is still joined.</param>
    /// <param name="cancellationToken">Cancels this caller's wait, never the shared flight.</param>
    /// <returns>The memoized notification KPI response.</returns>
    Task<NotificationKpiResponse> GetNotificationKpisAsync(
        bool forceRefresh = false, CancellationToken cancellationToken = default);

    /// <summary>Per-source-site Notification Outbox KPI breakdown.</summary>
    /// <param name="forceRefresh">Bypass a still-fresh value; an in-flight round is still joined.</param>
    /// <param name="cancellationToken">Cancels this caller's wait, never the shared flight.</param>
    /// <returns>The memoized per-site notification KPI response.</returns>
    Task<PerSiteNotificationKpiResponse> GetPerSiteNotificationKpisAsync(
        bool forceRefresh = false, CancellationToken cancellationToken = default);

    /// <summary>Per-node Notification Outbox KPI breakdown (grouped by <c>SourceNode</c>).</summary>
    /// <param name="forceRefresh">Bypass a still-fresh value; an in-flight round is still joined.</param>
    /// <param name="cancellationToken">Cancels this caller's wait, never the shared flight.</param>
    /// <returns>The memoized per-node notification KPI response.</returns>
    Task<PerNodeNotificationKpiResponse> GetPerNodeNotificationKpisAsync(
        bool forceRefresh = false, CancellationToken cancellationToken = default);

    /// <summary>Global Site Call Audit KPIs (buffered, stuck, parked).</summary>
    /// <param name="forceRefresh">Bypass a still-fresh value; an in-flight round is still joined.</param>
    /// <param name="cancellationToken">Cancels this caller's wait, never the shared flight.</param>
    /// <returns>The memoized site call KPI response.</returns>
    Task<SiteCallKpiResponse> GetSiteCallKpisAsync(
        bool forceRefresh = false, CancellationToken cancellationToken = default);

    /// <summary>Per-node Site Call Audit KPI breakdown (grouped by <c>SourceNode</c>).</summary>
    /// <param name="forceRefresh">Bypass a still-fresh value; an in-flight round is still joined.</param>
    /// <param name="cancellationToken">Cancels this caller's wait, never the shared flight.</param>
    /// <returns>The memoized per-node site call KPI response.</returns>
    Task<PerNodeSiteCallKpiResponse> GetPerNodeSiteCallKpisAsync(
        bool forceRefresh = false, CancellationToken cancellationToken = default);

    /// <summary>
    /// Audit Log KPI snapshot (1h volume + error rate over the central <c>AuditLog</c> table,
    /// plus the summed per-site backlog).
    /// </summary>
    /// <param name="forceRefresh">Bypass a still-fresh value; an in-flight round is still joined.</param>
    /// <param name="cancellationToken">Cancels this caller's wait, never the shared flight.</param>
    /// <returns>The memoized audit KPI snapshot.</returns>
    Task<AuditLogKpiSnapshot> GetAuditKpiSnapshotAsync(
        bool forceRefresh = false, CancellationToken cancellationToken = default);
}
