namespace AyCode.Core.Serializers.Binaries;

/// <summary>
/// Controls per-chunk flush synchronization on the parallel-capable Pipe-based send path
/// (<see cref="AsyncPipeWriterOutput"/>). Replaces the historical <c>bool waitForFlush</c>
/// parameter with three explicit memory-vs-throughput trade-off points.
///
/// <para><b>Stream-backed PipeWriter exception</b> — <see cref="System.IO.Pipelines.PipeWriter.Create(System.IO.Stream, System.IO.Pipelines.StreamPipeWriterOptions)"/>
/// (NamedPipe, FileStream, NetworkStream, etc.) is intrinsically sequential per chunk because of
/// the <c>StreamPipeWriter._tailMemory</c> reset race, regardless of policy. The auto-detected
/// sequential path is functionally equivalent to <see cref="PerChunk"/>. Only Pipe-based writers
/// (BCL <c>PipeWriterImpl</c>, Kestrel transport, custom parallel-capable impls) honour the policy
/// distinction between the three values.</para>
/// </summary>
public enum FlushPolicy
{
    /// <summary>
    /// Sequential — every chunk fully flushes and awaits completion before the next is acquired.
    /// Producer-side: commit → <c>FlushAsync</c> → await → acquire-next.
    /// <para><b>Peak memory:</b> ~chunk_size × 1 (one in-flight chunk).</para>
    /// <para><b>Pro:</b> strictly bounded peak memory regardless of consumer speed; simplest
    /// memory profile to reason about. Auto-applied on Stream-backed PipeWriter regardless of
    /// chosen policy.</para>
    /// <para><b>Con:</b> no producer/flush parallelism — wall-clock = sum of (serialize + flush)
    /// per chunk.</para>
    /// <para>Recommended for unpredictable / unbounded payloads where memory must stay strictly
    /// minimal regardless of consumer behaviour.</para>
    /// </summary>
    PerChunk,

    /// <summary>
    /// Double-buffered — fire-and-forget the previous flush; block at the NEXT chunk's <c>Grow</c>
    /// only if the previous flush hasn't completed yet. Allows two chunks in flight simultaneously:
    /// the one being serialised + the one being flushed.
    /// <para><b>Peak memory:</b> ~chunk_size × 2 (current + previous overlapping).</para>
    /// <para><b>Pro:</b> maximum producer/flush parallelism with bounded memory; serializer
    /// continues with the next chunk while the previous one's flush completes in parallel.
    /// Wall-clock = max(serialize, flush) × N_chunks instead of sum.</para>
    /// <para><b>Con:</b> a slow consumer propagates back as producer-thread blocking at the next
    /// <c>Grow</c> (bounded by <c>flushTimeout</c>).</para>
    /// <para>Recommended <b>default</b> for typical streaming scenarios — the best memory/throughput
    /// trade-off when the payload is sized comparably to or larger than chunk_size.</para>
    /// </summary>
    DoubleBuffered,

    /// <summary>
    /// Coalesced — producer batches up to ~64 KB worth of chunks into a single flush window.
    /// While a previous <c>FlushAsync</c> is in-flight, new chunks accumulate in the
    /// <see cref="System.IO.Pipelines.PipeWriter"/>'s buffer without firing additional flushes.
    /// When the per-window counter approaches the safety threshold (~64 KB), the producer waits
    /// for the in-flight flush to complete, then fires <b>one</b> batched flush covering the
    /// entire window. After firing, the window-counter resets and the next window begins.
    /// <para><b>Peak memory:</b> bounded per-window by ~64 KB (the in-flight chunks during one
    /// flush window). Total peak in process ≤ chunk_size × 2 + ~64 KB pipe-internal accumulation.</para>
    /// <para><b>Pro:</b> dramatically fewer FlushAsync syscalls compared to per-chunk modes —
    /// e.g. a 9.5 MB payload at 4 KB chunks fires ~150 flushes (one per ~64 KB window) instead of
    /// ~2 300 flushes (one per chunk). Major throughput win on transports where each FlushAsync
    /// has non-trivial overhead (network sockets, Kestrel WebSocket, kernel TCP buffers).</para>
    /// <para><b>Con:</b> per-window peak memory ~64 KB (vs chunk_size × 2 in
    /// <see cref="DoubleBuffered"/>); under heavy backpressure may fall back to an owned buffer
    /// (losing zero-copy for that chunk).</para>
    /// <para>Recommended when payload size is known and bounded (REST request/response, fixed-size
    /// IPC message), large enough to span multiple flush windows, and the consumer is reliably
    /// fast enough to drain the pipe between windows.</para>
    /// </summary>
    Coalesced
}
