import assert from "node:assert/strict";
import test from "node:test";
import {
  DEFAULT_EDGE_VOICES,
  createEdgeBrowserSynthesizer,
  rateToEdgePercent,
} from "../../lib/client/tts/edge-browser.ts";

test("chooses good default Mandarin and US English neural voices", () => {
  assert.deepEqual(DEFAULT_EDGE_VOICES, {
    "zh-CN": "zh-CN-XiaoxiaoNeural",
    "en-US": "en-US-AriaNeural",
  });
});

test("converts player speed to a bounded Edge prosody percentage", () => {
  assert.equal(rateToEdgePercent(0.5), "-50%");
  assert.equal(rateToEdgePercent(1), "+0%");
  assert.equal(rateToEdgePercent(1.25), "+25%");
  assert.equal(rateToEdgePercent(3), "+200%");
});

test("synthesizes a stored sentence as MP3 with the selected voice", async () => {
  const calls = [];
  const fakeAudio = new Blob([new Uint8Array([0x49, 0x44, 0x33])], { type: "audio/mpeg" });
  const synthesize = createEdgeBrowserSynthesizer(async () => ({
    EdgeTTS: class {
      constructor(text, voice, options) { calls.push({ text, voice, options }); }
      async synthesize() { return { audio: fakeAudio, subtitle: [] }; }
    },
  }));
  const result = await synthesize({ text: "你好。", voice: "zh-CN-XiaoxiaoNeural", rate: 1.2 });
  assert.equal(result, fakeAudio);
  assert.deepEqual(calls, [{
    text: "你好。", voice: "zh-CN-XiaoxiaoNeural",
    options: { rate: "+20%", volume: "+0%", pitch: "+0Hz" },
  }]);
});

test("classifies Edge service failures for browser speech fallback", async () => {
  const synthesize = createEdgeBrowserSynthesizer(async () => ({
    EdgeTTS: class { async synthesize() { throw new Error("WebSocket connection failed"); } },
  }));
  await assert.rejects(
    synthesize({ text: "Hello.", voice: "en-US-AriaNeural", rate: 1 }),
    (error) => error.code === "edge_tts_unavailable" && error.fallbackAllowed === true,
  );
});

test("retries a short-lived Edge service failure before falling back", async () => {
  let attempts = 0;
  const fakeAudio = new Blob([new Uint8Array([0x49, 0x44, 0x33])], { type: "audio/mpeg" });
  const delays = [];
  const synthesize = createEdgeBrowserSynthesizer(async () => ({
    EdgeTTS: class {
      async synthesize() {
        attempts += 1;
        if (attempts < 3) throw new Error("WebSocket connection failed");
        return { audio: fakeAudio };
      }
    },
  }), async (milliseconds) => delays.push(milliseconds));
  assert.equal(await synthesize({ text: "Hello.", voice: "en-US-AriaNeural", rate: 1 }), fakeAudio);
  assert.equal(attempts, 3);
  assert.deepEqual(delays, [250, 750]);
});
