namespace ZB.MOM.WW.MxGateway.Server.Workers;

/// <summary>Configurable options for worker client behavior.</summary>
public sealed class WorkerClientOptions
{
    /// <summary>Default maximum age of a heartbeat before the client enters faulted state.</summary>
    public static readonly TimeSpan DefaultHeartbeatGrace = TimeSpan.FromSeconds(15);

    /// <summary>Default interval for checking heartbeat staleness.</summary>
    public static readonly TimeSpan DefaultHeartbeatCheckInterval = TimeSpan.FromSeconds(1);

    /// <summary>Default timeout when the event queue is full.</summary>
    public static readonly TimeSpan DefaultEventChannelFullModeTimeout = TimeSpan.FromSeconds(5);

    /// <summary>
    ///     Default ceiling on the in-flight-command heartbeat skip. Mirrors
    ///     <see cref="ZB.MOM.WW.MxGateway.Worker.Ipc.WorkerPipeSessionOptions.DefaultHeartbeatStuckCeiling"/>
    ///     on the worker side. When a command has been in flight
    ///     longer than this, the gateway-side heartbeat watchdog fires
    ///     regardless of pending commands — a truly stuck COM call shouldn't
    ///     hide the worker forever.
    /// </summary>
    public static readonly TimeSpan DefaultHeartbeatStuckCeiling = TimeSpan.FromSeconds(75);

    /// <summary>Initializes options with default values.</summary>
    public WorkerClientOptions()
    {
        HeartbeatGrace = DefaultHeartbeatGrace;
        HeartbeatCheckInterval = DefaultHeartbeatCheckInterval;
        EventChannelCapacity = 1_024;
        EventChannelFullModeTimeout = DefaultEventChannelFullModeTimeout;
        MaxPendingCommands = 128;
        HeartbeatStuckCeiling = DefaultHeartbeatStuckCeiling;
    }

    /// <summary>Maximum allowed age of the last heartbeat before faulting the client.</summary>
    public TimeSpan HeartbeatGrace { get; init; }

    /// <summary>Interval at which to check for heartbeat expiration.</summary>
    public TimeSpan HeartbeatCheckInterval { get; init; }

    /// <summary>Maximum number of events buffered before backpressure is applied.</summary>
    public int EventChannelCapacity { get; init; }

    /// <summary>
    ///     Time to wait for the gateway-side event channel to drain before
    ///     faulting the worker. Honored by <c>EnqueueWorkerEventAsync</c> via
    ///     <c>WriteAsync</c>; with the channel configured for
    ///     <c>BoundedChannelFullMode.Wait</c>, a transient backlog only faults
    ///     after the configured timeout has elapsed.
    /// </summary>
    public TimeSpan EventChannelFullModeTimeout { get; init; }

    /// <summary>Maximum number of concurrent pending commands.</summary>
    public int MaxPendingCommands { get; init; }

    /// <summary>
    ///     Ceiling on the in-flight-command heartbeat-skip. When
    ///     a command has been pending on the gateway↔worker pipe for longer
    ///     than this, the gateway-side <c>HeartbeatLoopAsync</c> fires the
    ///     <c>HeartbeatExpired</c> fault even if commands are still pending;
    ///     a truly stuck COM call shouldn't keep the watchdog suppressed
    ///     indefinitely. Mirrors <c>HeartbeatStuckCeiling</c> on
    ///     the worker side.
    /// </summary>
    public TimeSpan HeartbeatStuckCeiling { get; init; }
}
