using System.IO.Pipes;

namespace ZB.MOM.WW.MxGateway.Tests.TestSupport;

/// <summary>
/// Creates the gateway-side <see cref="NamedPipeServerStream"/> that in-process worker fakes connect
/// to, with an explicit OS buffer so a test that deliberately stops draining the pipe cannot block
/// its own writer forever.
/// </summary>
/// <remarks>
/// The <c>NamedPipeServerStream(string, PipeDirection, int, PipeTransmissionMode, PipeOptions)</c>
/// overload passes <c>inBufferSize: 0</c> and <c>outBufferSize: 0</c> to <c>CreateNamedPipe</c>. On
/// Windows that reserves <em>no</em> buffer at all: a write completes only once the peer reads it —
/// measured on a Windows 10 host, the very first 63-byte write to a non-reading peer never completed,
/// against 65 520 bytes absorbed by the same pipe declared with 64 KiB buffers. On macOS and Linux
/// .NET backs named pipes with Unix domain sockets, whose socket buffer absorbs several kilobytes
/// regardless, so the zero-buffer declaration is invisible there.
/// <para>
/// That asymmetry wedged the whole Windows test host: <c>WorkerClientTests</c> pushes events past the
/// worker client's staging bound to prove the client faults, and after the fault the client's read
/// loop stops by design. On Windows the next test-side write then blocked forever with no timeout, so
/// the test never returned, xUnit never raised <c>ITestAssemblyFinished</c>, and <c>testhost</c> never
/// exited even though every other test had already passed.
/// </para>
/// <para>
/// Buffering the test pipe scopes those tests to the behavior they are actually asserting — the
/// gateway's own staging/queue backpressure — instead of the OS pipe's flow control. The gateway's
/// production pipe in <c>SessionWorkerClientFactory</c> keeps the unbuffered declaration on purpose:
/// there both ends run continuous read loops and every write is bounded by the worker client's stop
/// token, so a stalled peer cancels rather than blocks.
/// </para>
/// </remarks>
internal static class TestNamedPipe
{
    /// <summary>
    /// The buffer reserved for each direction. Comfortably larger than any frame volume a test
    /// pushes at a stopped reader, and the size Windows itself uses for a typical named pipe.
    /// </summary>
    internal const int BufferBytes = 64 * 1024;

    /// <summary>Creates the gateway-side server pipe for <paramref name="pipeName"/>.</summary>
    /// <param name="pipeName">The pipe name the fake worker connects to.</param>
    /// <returns>An asynchronous, byte-mode server pipe with explicit buffers.</returns>
    internal static NamedPipeServerStream CreateServer(string pipeName)
    {
        return new NamedPipeServerStream(
            pipeName,
            PipeDirection.InOut,
            maxNumberOfServerInstances: 1,
            PipeTransmissionMode.Byte,
            PipeOptions.Asynchronous,
            inBufferSize: BufferBytes,
            outBufferSize: BufferBytes);
    }
}
