namespace TeamsISO.Engine.Pipeline;

/// <summary>
/// Tap point for per-ISO output recording. Each <see cref="IsoPipeline"/> can be
/// wired with one recorder; when present, every <see cref="ProcessedFrame"/> that
/// flows from <see cref="FrameProcessor"/> to <see cref="NdiSender"/> is also fed
/// to the recorder for persistence to disk.
///
/// Lifecycle:
///   1. <see cref="Open"/> is called once when the pipeline starts (or restarts).
///   2. <see cref="WriteFrame"/> is called for every processed frame, in order.
///   3. <see cref="Close"/> is called once when the pipeline stops or fails.
///
/// Implementations must be tolerant of out-of-order calls (Close before Open,
/// double Close, WriteFrame after Close) — the supervisor's restart logic can
/// race in unusual ways. The simplest correct implementation is to track an
/// <c>_isOpen</c> flag and short-circuit when not open.
/// </summary>
public interface IRecorderSink : IAsyncDisposable
{
    /// <summary>
    /// Open the underlying file/encoder and prepare to receive frames. Width/Height
    /// match the pipeline's normalized output resolution; FPS is the target framerate
    /// (incoming frames may arrive with timing jitter, but the recorder writes at the
    /// nominal rate for downstream playback consistency).
    /// </summary>
    /// <param name="participantDisplayName">Used to derive the output filename.</param>
    /// <param name="outputDirectory">Directory under which the recording is created.</param>
    /// <param name="width">Frame width in pixels.</param>
    /// <param name="height">Frame height in pixels.</param>
    /// <param name="fps">Nominal framerate.</param>
    void Open(string participantDisplayName, string outputDirectory, int width, int height, double fps);

    /// <summary>
    /// Write one processed frame. Implementations should not block — if encoding is
    /// expensive, queue the frame to a worker thread and return promptly. Returning
    /// false means the recorder dropped the frame (disk full, queue overflow); the
    /// pipeline carries on regardless so a recorder failure never kills the live ISO.
    /// </summary>
    bool WriteFrame(ProcessedFrame frame);

    /// <summary>
    /// Flush and finalize the output. Idempotent.
    /// </summary>
    void Close();

    /// <summary>True between successful <see cref="Open"/> and <see cref="Close"/>.</summary>
    bool IsRecording { get; }

    /// <summary>
    /// Drop a timestamped marker into the recording. Used by the operator to
    /// chapter a recording in real time — "host intro starts here", "guest
    /// answer", etc. — so post-production can jump to the right moment without
    /// scrubbing through the raw stream. The label is free-form; an empty
    /// label means "unnamed marker." No-op when not recording.
    /// </summary>
    void AddMarker(string label);
}
