using DragonISO.Engine.Pipeline;

namespace DragonISO.Engine.Interop;

/// <summary>
/// Test seam over the NDI SDK. Production: P/Invoke shim. Tests: <c>FakeNdiInterop</c>.
/// All methods are synchronous; the engine threads are responsible for orchestration.
/// </summary>
public interface INdiInterop
{
    // ----- Discovery -----

    /// <summary>
    /// Creates an NDI finder that observes sources advertised on the given groups.
    /// </summary>
    /// <param name="groups">
    /// Comma-separated list of NDI group names to subscribe to. <c>null</c> or empty
    /// uses the NDI default (<c>"Public"</c>). Whitespace around commas is tolerated.
    /// </param>
    NdiFindHandle CreateFinder(string? groups = null);

    /// <summary>Snapshots the currently-known sources visible to the finder.</summary>
    IReadOnlyList<string> GetCurrentSources(NdiFindHandle finder);

    // ----- Receive -----
    NdiReceiverHandle CreateReceiver(string sourceFullName);

    /// <summary>
    /// Blocks for up to <paramref name="timeoutMs"/> waiting for a frame.
    /// Returns null on timeout. Returned <see cref="RawFrame"/> ownership transfers to the caller.
    /// </summary>
    RawFrame? CaptureFrame(NdiReceiverHandle receiver, int timeoutMs);

    /// <summary>
    /// Pulls the next audio frame from the receiver and returns its peak
    /// amplitude in [0.0, 1.0], or <c>null</c> if no audio frame was available
    /// within the timeout. Implementations MUST return immediately when no
    /// audio is queued (a polling caller drives a UI VU bar; we don't want it
    /// to block on a video-only sender).
    ///
    /// Default implementation returns null â€” the <see cref="FakeNdiInterop"/>
    /// in tests doesn't simulate audio; the production
    /// <c>NdiInteropPInvoke</c> overrides this with the real read.
    /// </summary>
    double? CaptureAudioPeak(NdiReceiverHandle receiver, int timeoutMs) => null;

    // ----- Send -----

    /// <summary>
    /// Creates an NDI sender broadcasting on the given groups.
    /// </summary>
    /// <param name="outputName">The NDI source name segment (the part inside parens).</param>
    /// <param name="groups">
    /// Comma-separated list of NDI group names to broadcast on. <c>null</c> or empty
    /// uses the NDI default (<c>"Public"</c>).
    /// </param>
    NdiSenderHandle CreateSender(string outputName, string? groups = null);

    void SendFrame(NdiSenderHandle sender, ProcessedFrame frame);

    // ----- Runtime probe -----
    string GetRuntimeVersion();
}
