using System;
using System.Runtime.InteropServices;

namespace ZB.MOM.WW.MxGateway.Worker.Sta;

/// <summary>
///     The single declaration of the Win32 wait the worker's STA is built on.
///     Both waiters use it: <see cref="StaMessagePump"/> for the runtime's outer
///     idle wait, and <see cref="StaWaitHelper"/> for the inner completion waits
///     a command performs while it already holds the apartment.
/// </summary>
/// <remarks>
///     Deliberately one copy. This is the subtlest Win32 contract in the worker —
///     the wake mask decides which events can wake the STA, and
///     <see cref="MwmoInputAvailable"/> decides whether a message already seen by
///     a <c>PeekMessage</c> still counts as a wake. Two copies of it could drift
///     apart silently, and a divergence would show up only as COM events
///     arriving late on a live provider.
/// </remarks>
internal static class StaNativeMethods
{
    /// <summary>Return value of a failed wait (<c>WAIT_FAILED</c>).</summary>
    internal const uint MsgWaitFailed = 0xFFFFFFFF;

    /// <summary>
    ///     Wake even when the pending input has already been seen (but not
    ///     removed) by an earlier <c>PeekMessage</c>. Both callers peek before
    ///     they wait, so without this flag a message that arrived during the peek
    ///     would not wake the wait that follows it.
    /// </summary>
    internal const uint MwmoInputAvailable = 0x0004;

    /// <summary>Wake on any queued input, including sent and posted messages.</summary>
    internal const uint QsAllInput = 0x04FF;

    /// <summary>
    ///     Waits for the given handles, for queued input matching
    ///     <paramref name="wakeMask"/>, or for the timeout — whichever comes
    ///     first.
    /// </summary>
    /// <param name="count">Number of handles in <paramref name="handles"/>.</param>
    /// <param name="handles">Handles to wait on; marshaled as a pointer to the array.</param>
    /// <param name="milliseconds">Timeout in milliseconds; <c>0xFFFFFFFF</c> means INFINITE.</param>
    /// <param name="wakeMask">Input types that may wake the wait (<see cref="QsAllInput"/>).</param>
    /// <param name="flags">Wait flags (<see cref="MwmoInputAvailable"/>).</param>
    /// <returns>
    ///     <c>WAIT_OBJECT_0 + i</c> for a signaled handle, <c>WAIT_OBJECT_0 + count</c>
    ///     for available input, <c>WAIT_TIMEOUT</c> (258), or
    ///     <see cref="MsgWaitFailed"/>.
    /// </returns>
    [DllImport("user32.dll", SetLastError = true)]
    internal static extern uint MsgWaitForMultipleObjectsEx(
        uint count,
        IntPtr[] handles,
        uint milliseconds,
        uint wakeMask,
        uint flags);
}
