import { describe, expect, it, vi } from "vitest";
import { Future } from "../../utils.js";
import { ParticipantAudioOutput } from "./_output.js";
const nextTick = () => new Promise((resolve) => setImmediate(resolve));
describe("ParticipantAudioOutput waitForPlayoutTask", () => {
  it("resets tracked duration after non-interrupted playout", async () => {
    let resolvePlayout;
    const waitForPlayout = new Promise((resolve) => {
      resolvePlayout = resolve;
    });
    const output = Object.create(ParticipantAudioOutput.prototype);
    const onPlaybackFinished = vi.fn();
    output.pushedDuration = 1;
    output.interruptedFuture = new Future();
    output.firstFrameEmitted = true;
    output.onPlaybackFinished = onPlaybackFinished;
    output.audioSource = {
      waitForPlayout: () => waitForPlayout,
      queuedDuration: 0,
      clearQueue: vi.fn()
    };
    const task = output.waitForPlayoutTask(new AbortController());
    resolvePlayout();
    await task;
    expect(output.pushedDuration).toBe(0);
    expect(onPlaybackFinished).toHaveBeenCalledWith({
      playbackPosition: 1,
      interrupted: false
    });
  });
  it("resets duration to queue state when interrupted flush clears overlap", async () => {
    let resolvePlayout;
    const waitForPlayout = new Promise((resolve) => {
      resolvePlayout = resolve;
    });
    const output = Object.create(ParticipantAudioOutput.prototype);
    const onPlaybackFinished = vi.fn();
    output.pushedDuration = 1;
    output.interruptedFuture = new Future();
    output.firstFrameEmitted = true;
    output.onPlaybackFinished = onPlaybackFinished;
    output.audioSource = {
      waitForPlayout: () => waitForPlayout,
      queuedDuration: 500,
      clearQueue: vi.fn(() => {
        output.audioSource.queuedDuration = 0;
      })
    };
    const task = output.waitForPlayoutTask(new AbortController());
    output.pushedDuration += 0.5;
    output.interruptedFuture.resolve();
    resolvePlayout();
    await task;
    expect(output.pushedDuration).toBe(0);
    expect(onPlaybackFinished).toHaveBeenCalledWith({
      playbackPosition: 0.5,
      interrupted: true
    });
  });
  it("does not finish one segment twice when flush is called again before playout drains", async () => {
    let resolvePlayout;
    const waitForPlayout = new Promise((resolve) => {
      resolvePlayout = resolve;
    });
    const output = Object.create(ParticipantAudioOutput.prototype);
    const onPlaybackFinished = vi.fn();
    output.pushedDuration = 1;
    output.interruptedFuture = new Future();
    output.firstFrameEmitted = true;
    output.onPlaybackFinished = onPlaybackFinished;
    output.logger = {
      error: vi.fn()
    };
    output.audioSource = {
      waitForPlayout: () => waitForPlayout,
      queuedDuration: 0,
      clearQueue: vi.fn()
    };
    output.flush();
    await nextTick();
    output.flush();
    await nextTick();
    resolvePlayout();
    await nextTick();
    expect(onPlaybackFinished).toHaveBeenCalledTimes(1);
    expect(onPlaybackFinished).toHaveBeenCalledWith({
      playbackPosition: 1,
      interrupted: false
    });
    expect(output.logger.error).not.toHaveBeenCalled();
  });
});
describe("ParticipantAudioOutput captureFrame segment accounting", () => {
  const makeOutput = (opts) => {
    const output = Object.create(ParticipantAudioOutput.prototype);
    output.startedFuture = new Future();
    output.startedFuture.resolve();
    output.playbackEnabledFuture = new Future();
    if (!opts.paused) output.playbackEnabledFuture.resolve();
    output.interruptedFuture = new Future();
    output.firstFrameEmitted = false;
    output.pushedDuration = 0;
    output._capturing = false;
    output.playbackSegmentsCount = 0;
    output.playbackFinishedCount = 0;
    output.playbackFinishedFuture = new Future();
    output.onPlaybackStarted = vi.fn();
    output.audioSource = { clearQueue: vi.fn(), captureFrame: vi.fn(async () => {
    }) };
    return output;
  };
  const frame = () => ({ samplesPerChannel: 480, sampleRate: 24e3 });
  it("does not strand the segment counter when a frame is interrupted while paused", async () => {
    const output = makeOutput({ paused: true });
    const capture = output.captureFrame(frame());
    output.interruptedFuture.resolve();
    await capture;
    expect(output.playbackSegmentsCount).toBe(0);
    expect(output.audioSource.captureFrame).not.toHaveBeenCalled();
    const result = await Promise.race([
      output.waitForPlayout().then(() => "resolved"),
      new Promise((resolve) => setTimeout(() => resolve("timeout"), 1e3))
    ]);
    expect(result).toBe("resolved");
  });
  it("registers a segment on the normal non-paused path", async () => {
    const output = makeOutput({ paused: false });
    await output.captureFrame(frame());
    expect(output.playbackSegmentsCount).toBe(1);
    expect(output.audioSource.captureFrame).toHaveBeenCalledTimes(1);
    expect(output.pushedDuration).toBeGreaterThan(0);
  });
});
//# sourceMappingURL=_output.test.js.map