"use strict";
var import_vitest = require("vitest");
var import_base = require("./base.cjs");
var import_languages = require("./languages.cjs");
class FakeTransport {
  events = [];
  _stream;
  attach(stream) {
    this._stream = stream;
  }
  async run() {
    if (this._stream === void 0) {
      throw new Error("stream not bound");
    }
    await this._stream._drainAudioChannel();
  }
  runInference(requestId) {
    this.events.push(["run_inference", requestId]);
  }
  async pushFrame(_frame) {
  }
  async flush(_sentinel) {
  }
  detach() {
  }
}
class FakeDetector extends import_base.BaseStreamingTurnDetector {
  // Default to the local mini model so the timed-out-cancel test sees a
  // non-cloud model and skips the fallback.
  get model() {
    return "turn-detector-v1-mini";
  }
  stream() {
    throw new Error("unused in request-lifecycle tests");
  }
}
class FakeBackend extends import_base.BaseStreamingTurnDetectorStream {
  fakeTransport;
  constructor(opts) {
    const transport = new FakeTransport();
    super({ detector: new FakeDetector(opts), opts, transport });
    this.fakeTransport = transport;
  }
  get events() {
    return this.fakeTransport.events;
  }
  /** Mirror what a transport would do: hand the prediction to the stream. */
  simulatePrediction(requestId, probability) {
    this._resolvePrediction(requestId, probability);
  }
  // Exposed for assertions.
  get requestId() {
    return this._requestId;
  }
  get requestFut() {
    return this._requestFut;
  }
}
function makeOpts(thresholds = {}) {
  return {
    sampleRate: 16e3,
    thresholds: new import_languages.ThresholdOptions("turn-detector-v1-mini", thresholds)
  };
}
function makeStream(thresholds = {}) {
  return new FakeBackend(makeOpts(thresholds));
}
const countRunInference = (events) => events.filter((e) => e[0] === "run_inference").length;
(0, import_vitest.describe)("AudioTurnDetectionRequests", () => {
  (0, import_vitest.it)("predict starts inference", async () => {
    const s = makeStream();
    try {
      const fut = s.predict();
      (0, import_vitest.expect)(s.requestId).toBeDefined();
      (0, import_vitest.expect)(fut.done).toBe(false);
      (0, import_vitest.expect)(s.events).toEqual([["run_inference", s.requestId]]);
    } finally {
      await s.aclose();
    }
  });
  (0, import_vitest.it)("predict supersedes previous request", async () => {
    const s = makeStream();
    try {
      const oldFut = s.predict();
      const oldId = s.requestId;
      const newFut = s.predict();
      (0, import_vitest.expect)(newFut).not.toBe(oldFut);
      (0, import_vitest.expect)(s.requestId).not.toBe(oldId);
      (0, import_vitest.expect)(oldFut.done).toBe(true);
      (0, import_vitest.expect)((await oldFut.await).endOfTurnProbability).toBe(0);
      (0, import_vitest.expect)(countRunInference(s.events)).toBe(2);
    } finally {
      await s.aclose();
    }
  });
  (0, import_vitest.it)("cancelInference closes the request", async () => {
    const s = makeStream();
    try {
      const fut = s.predict();
      s.cancelInference();
      (0, import_vitest.expect)(s.requestId).toBeUndefined();
      (0, import_vitest.expect)(fut.done).toBe(true);
      (0, import_vitest.expect)((await fut.await).endOfTurnProbability).toBe(0);
    } finally {
      await s.aclose();
    }
  });
  (0, import_vitest.it)("cancelInference when idle is a no-op", async () => {
    const s = makeStream();
    try {
      s.cancelInference();
      (0, import_vitest.expect)(s.events).toEqual([]);
    } finally {
      await s.aclose();
    }
  });
  (0, import_vitest.it)("late prediction after cancelInference is dropped", async () => {
    const s = makeStream();
    try {
      const fut = s.predict();
      const cancelledId = s.requestId;
      (0, import_vitest.expect)(cancelledId).toBeDefined();
      s.cancelInference();
      s.simulatePrediction(cancelledId, 0.9);
      (0, import_vitest.expect)((await fut.await).endOfTurnProbability).toBe(0);
      const nextFut = s.predict();
      (0, import_vitest.expect)(nextFut).not.toBe(fut);
      (0, import_vitest.expect)(nextFut.done).toBe(false);
      (0, import_vitest.expect)(countRunInference(s.events)).toBe(2);
    } finally {
      await s.aclose();
    }
  });
  (0, import_vitest.it)("prediction completes the request", async () => {
    const s = makeStream();
    try {
      const fut = s.predict();
      const requestId = s.requestId;
      (0, import_vitest.expect)(requestId).toBeDefined();
      s.simulatePrediction(requestId, 0.3);
      (0, import_vitest.expect)(fut.done).toBe(true);
      (0, import_vitest.expect)((await fut.await).endOfTurnProbability).toBe(0.3);
      (0, import_vitest.expect)(s.requestId).toBeUndefined();
    } finally {
      await s.aclose();
    }
  });
  (0, import_vitest.it)("flush closes the request", async () => {
    const s = makeStream();
    try {
      const fut = s.predict();
      s.flush("turn committed");
      (0, import_vitest.expect)(s.requestId).toBeUndefined();
      (0, import_vitest.expect)((await fut.await).endOfTurnProbability).toBe(0);
    } finally {
      await s.aclose();
    }
  });
  (0, import_vitest.it)("flush does not overwrite a resolved prediction", async () => {
    const s = makeStream();
    try {
      const fut = s.predict();
      const requestId = s.requestId;
      (0, import_vitest.expect)(requestId).toBeDefined();
      s.simulatePrediction(requestId, 0.7);
      s.flush("turn committed");
      (0, import_vitest.expect)((await fut.await).endOfTurnProbability).toBe(0.7);
      (0, import_vitest.expect)(s.requestId).toBeUndefined();
    } finally {
      await s.aclose();
    }
  });
  (0, import_vitest.it)("predict after endInput returns a resolved default", async () => {
    const s = makeStream();
    try {
      s.endInput();
      await new Promise((resolve) => setTimeout(resolve, 20));
      const fut = s.predict();
      (0, import_vitest.expect)(fut.done).toBe(true);
      (0, import_vitest.expect)((await fut.await).endOfTurnProbability).toBe(1);
      (0, import_vitest.expect)(s.events.some((e) => e[0] === "run_inference")).toBe(false);
    } finally {
      await s.aclose();
    }
  });
  (0, import_vitest.it)("aclose resolves a pending future", async () => {
    const s = makeStream();
    const fut = s.predict();
    await s.aclose();
    (0, import_vitest.expect)(fut.done).toBe(true);
    (0, import_vitest.expect)((await fut.await).endOfTurnProbability).toBe(0);
  });
  (0, import_vitest.it)("timed-out cancelInference does not fall back for the local model", async () => {
    const s = makeStream();
    try {
      const fut = s.predict();
      s.cancelInference({ timedOut: true });
      (0, import_vitest.expect)((await fut.await).endOfTurnProbability).toBe(0);
      (0, import_vitest.expect)(s.model).toBe("turn-detector-v1-mini");
    } finally {
      await s.aclose();
    }
  });
});
//# sourceMappingURL=base.test.cjs.map