import test from "node:test";
import assert from "node:assert/strict";

const { handleAudioSpeech } = await import("../../open-sse/handlers/audioSpeech.ts");
const { AUDIO_SPEECH_PROVIDERS } = await import("../../open-sse/config/audioRegistry.ts");

test("handleAudioSpeech requires model", async () => {
  const response = await handleAudioSpeech({
    body: { input: "hello" },
    credentials: { apiKey: "x" },
  });
  const payload = (await response.json()) as any;

  assert.equal(response.status, 400);
  assert.equal(payload.error.message, "model is required");
});

test("handleAudioSpeech requires input text", async () => {
  const response = await handleAudioSpeech({
    body: { model: "openai/tts-1" },
    credentials: { apiKey: "x" },
  });
  const payload = (await response.json()) as any;

  assert.equal(response.status, 400);
  assert.equal(payload.error.message, "input is required");
});

test("handleAudioSpeech proxies OpenAI-compatible providers with defaults", async () => {
  const originalFetch = globalThis.fetch;
  let captured;

  globalThis.fetch = async (url, options = {}) => {
    captured = {
      url: String(url),
      headers: options.headers,
      body: JSON.parse(String(options.body || "{}")),
    };

    return new Response(new Uint8Array([1, 2, 3]), {
      status: 200,
      headers: { "content-type": "audio/opus" },
    });
  };

  try {
    const response = await handleAudioSpeech({
      body: {
        model: "openai/tts-1",
        input: "hello world",
      },
      credentials: { apiKey: "openai-key" },
    });

    assert.equal(captured.url, "https://api.openai.com/v1/audio/speech");
    assert.equal(captured.headers.Authorization, "Bearer openai-key");
    assert.deepEqual(captured.body, {
      model: "tts-1",
      input: "hello world",
      voice: "alloy",
      response_format: "mp3",
      speed: 1,
    });
    assert.equal(response.status, 200);
    assert.equal(response.headers.get("content-type"), "audio/opus");
    assert.match(response.headers.get("access-control-allow-methods") || "", /OPTIONS/);
  } finally {
    globalThis.fetch = originalFetch;
  }
});

test("handleAudioSpeech routes Deepgram with Token auth and model query parameter", async () => {
  const originalFetch = globalThis.fetch;
  let capturedUrl;
  let capturedHeaders;

  globalThis.fetch = async (url, options = {}) => {
    capturedUrl = String(url);
    capturedHeaders = options.headers;
    const body = JSON.parse(String(options.body || "{}"));
    assert.deepEqual(body, { text: "deepgram text" });

    return new Response(new Uint8Array([9, 8, 7]), {
      status: 200,
      headers: { "content-type": "audio/mpeg" },
    });
  };

  try {
    const response = await handleAudioSpeech({
      body: {
        model: "deepgram/aura-asteria-en",
        input: "deepgram text",
      },
      credentials: { apiKey: "dg-key" },
    });

    const url = new URL(capturedUrl);
    assert.equal(url.origin + url.pathname, "https://api.deepgram.com/v1/speak");
    assert.equal(url.searchParams.get("model"), "aura-asteria-en");
    assert.equal(capturedHeaders.Authorization, "Token dg-key");
    assert.equal(response.status, 200);
  } finally {
    globalThis.fetch = originalFetch;
  }
});

test("handleAudioSpeech rejects invalid ElevenLabs voice identifiers", async () => {
  const originalFetch = globalThis.fetch;
  let called = false;
  globalThis.fetch = async () => {
    called = true;
    throw new Error("should not fetch");
  };

  try {
    const response = await handleAudioSpeech({
      body: {
        model: "elevenlabs/eleven_turbo_v2_5",
        input: "bad voice",
        voice: "../secret",
      },
      credentials: { apiKey: "xi-key" },
    });
    const payload = (await response.json()) as any;

    assert.equal(response.status, 400);
    assert.equal(payload.error.message, "Invalid voice ID");
    assert.equal(called, false);
  } finally {
    globalThis.fetch = originalFetch;
  }
});

test("handleAudioSpeech maps Cartesia voice and wav output settings", async () => {
  const originalFetch = globalThis.fetch;
  let captured;

  globalThis.fetch = async (_url, options = {}) => {
    captured = {
      headers: options.headers,
      body: JSON.parse(String(options.body || "{}")),
    };
    return new Response(new Uint8Array([4, 5, 6]), {
      status: 200,
      headers: { "content-type": "audio/wav" },
    });
  };

  try {
    const response = await handleAudioSpeech({
      body: {
        model: "cartesia/sonic-2",
        input: "cartesia text",
        voice: "voice-123",
        response_format: "wav",
      },
      credentials: { apiKey: "cartesia-key" },
    });

    assert.equal(captured.headers["X-API-Key"], "cartesia-key");
    assert.equal(captured.headers["Cartesia-Version"], "2024-06-10");
    assert.deepEqual(captured.body, {
      model_id: "sonic-2",
      transcript: "cartesia text",
      voice: { mode: "id", id: "voice-123" },
      output_format: { container: "wav", sample_rate: 44100 },
    });
    assert.equal(response.headers.get("content-type"), "audio/wav");
  } finally {
    globalThis.fetch = originalFetch;
  }
});

test("handleAudioSpeech maps PlayHT credentials, output format, and speed", async () => {
  const originalFetch = globalThis.fetch;
  let captured;

  globalThis.fetch = async (_url, options = {}) => {
    captured = {
      headers: options.headers,
      body: JSON.parse(String(options.body || "{}")),
    };
    return new Response(new Uint8Array([7, 7, 7]), {
      status: 200,
      headers: { "content-type": "audio/mpeg" },
    });
  };

  try {
    const response = await handleAudioSpeech({
      body: {
        model: "playht/Play3.0-mini",
        input: "playht text",
        response_format: "aac",
        speed: 1.25,
      },
      credentials: { apiKey: "user-1:api-key-1" },
    });

    assert.equal(captured.headers["X-USER-ID"], "user-1");
    assert.equal(captured.headers.Authorization, "Bearer api-key-1");
    assert.equal(captured.body.voice_engine, "Play3.0-mini");
    assert.equal(captured.body.output_format, "aac");
    assert.equal(captured.body.speed, 1.25);
    assert.equal(response.status, 200);
  } finally {
    globalThis.fetch = originalFetch;
  }
});

test("handleAudioSpeech signs AWS Polly synthesize requests with SigV4", async () => {
  const originalFetch = globalThis.fetch;
  let captured;

  globalThis.fetch = async (url, options = {}) => {
    captured = {
      url: String(url),
      headers: options.headers as Record<string, string>,
      body: JSON.parse(String(options.body || "{}")),
    };

    return new Response(new Uint8Array([8, 8, 8]), {
      status: 200,
      headers: { "content-type": "audio/ogg" },
    });
  };

  try {
    const response = await handleAudioSpeech({
      body: {
        model: "aws-polly/neural",
        input: "hello from polly",
        voice: "Joanna",
        response_format: "opus",
        language_code: "en-US",
        sample_rate: "48000",
      },
      credentials: {
        apiKey: "aws-secret-key",
        providerSpecificData: {
          accessKeyId: "AKIA_TEST",
          region: "us-west-2",
        },
      },
    });

    assert.equal(captured.url, "https://polly.us-west-2.amazonaws.com/v1/speech");
    assert.equal(captured.headers["content-type"], "application/json");
    assert.equal(captured.headers["x-amz-content-sha256"].length, 64);
    assert.match(
      captured.headers.Authorization,
      /^AWS4-HMAC-SHA256 Credential=AKIA_TEST\/\d{8}\/us-west-2\/polly\/aws4_request,/
    );
    assert.deepEqual(captured.body, {
      Engine: "neural",
      OutputFormat: "ogg_opus",
      Text: "hello from polly",
      TextType: "text",
      VoiceId: "Joanna",
      LanguageCode: "en-US",
      SampleRate: "48000",
    });
    assert.equal(response.status, 200);
    assert.equal(response.headers.get("content-type"), "audio/ogg");
  } finally {
    globalThis.fetch = originalFetch;
  }
});

test("handleAudioSpeech maps Xiaomi MiMo TTS to chat completions audio payload", async () => {
  const originalFetch = globalThis.fetch;
  let captured;

  globalThis.fetch = async (url, options = {}) => {
    captured = {
      url: String(url),
      headers: options.headers,
      body: JSON.parse(String(options.body || "{}")),
    };

    return new Response(
      JSON.stringify({
        choices: [{ message: { audio: { data: "AQID" } } }],
      }),
      {
        status: 200,
        headers: { "content-type": "application/json" },
      }
    );
  };

  try {
    const response = await handleAudioSpeech({
      body: {
        model: "xiaomi-mimo/mimo-v2.5-tts",
        input: "mimo text",
        voice: "default_zh",
        response_format: "wav",
      },
      credentials: {
        apiKey: "xm-key",
        providerSpecificData: {
          baseUrl: "https://token-plan-sgp.xiaomimimo.com/v1",
        },
      },
    });

    assert.equal(captured.url, "https://token-plan-sgp.xiaomimimo.com/v1/chat/completions");
    assert.equal(captured.headers.Authorization, "Bearer xm-key");
    assert.deepEqual(captured.body, {
      model: "mimo-v2.5-tts",
      messages: [{ role: "assistant", content: "mimo text" }],
      audio: { format: "audio/wav", voice: "default_zh" },
    });
    assert.equal(response.status, 200);
    assert.equal(response.headers.get("content-type"), "audio/wav");
    assert.deepEqual(Array.from(new Uint8Array(await response.arrayBuffer())), [1, 2, 3]);
  } finally {
    globalThis.fetch = originalFetch;
  }
});

test("handleAudioSpeech rejects unsupported Xiaomi MiMo TTS audio formats", async () => {
  const response = await handleAudioSpeech({
    body: {
      model: "xiaomi-mimo/mimo-v2.5-tts",
      input: "mimo text",
      response_format: "opus",
    },
    credentials: { apiKey: "xm-key" },
  });
  const payload = (await response.json()) as any;

  assert.equal(response.status, 400);
  assert.equal(payload.error.message, "Xiaomi MiMo TTS supports response_format mp3 or wav only");
});

test("handleAudioSpeech requires credentials for authenticated providers", async () => {
  const response = await handleAudioSpeech({
    body: {
      model: "openai/tts-1",
      input: "hello world",
    },
    credentials: null,
  });
  const payload = (await response.json()) as any;

  assert.equal(response.status, 401);
  assert.equal(payload.error.message, "No credentials for speech provider: openai");
});

test("handleAudioSpeech decodes Hyperbolic base64 audio responses", async () => {
  const originalFetch = globalThis.fetch;
  let capturedBody;

  globalThis.fetch = async (_url, options = {}) => {
    capturedBody = JSON.parse(String(options.body || "{}"));

    return new Response(JSON.stringify({ audio: "AQID" }), {
      status: 200,
      headers: { "content-type": "application/json" },
    });
  };

  try {
    const response = await handleAudioSpeech({
      body: {
        model: "hyperbolic/melo-tts",
        input: "hyperbolic text",
      },
      credentials: { apiKey: "hyper-key" },
    });

    assert.deepEqual(capturedBody, { text: "hyperbolic text" });
    assert.equal(response.status, 200);
    assert.equal(response.headers.get("content-type"), "audio/mpeg");
    assert.deepEqual(Array.from(new Uint8Array(await response.arrayBuffer())), [1, 2, 3]);
  } finally {
    globalThis.fetch = originalFetch;
  }
});

test("handleAudioSpeech routes Nvidia TTS providers with default voice", async () => {
  const originalFetch = globalThis.fetch;
  let captured;

  globalThis.fetch = async (_url, options = {}) => {
    captured = {
      headers: options.headers,
      body: JSON.parse(String(options.body || "{}")),
    };

    return new Response(new Uint8Array([3, 2, 1]), {
      status: 200,
      headers: { "content-type": "audio/wav" },
    });
  };

  try {
    const response = await handleAudioSpeech({
      body: {
        model: "nvidia/nvidia/fastpitch",
        input: "nvidia text",
      },
      credentials: { apiKey: "nvidia-key" },
    });

    assert.equal(captured.headers.Authorization, "Bearer nvidia-key");
    assert.deepEqual(captured.body, {
      input: { text: "nvidia text" },
      voice: "default",
      model: "nvidia/fastpitch",
    });
    assert.equal(response.status, 200);
    assert.equal(response.headers.get("content-type"), "audio/wav");
  } finally {
    globalThis.fetch = originalFetch;
  }
});

test("handleAudioSpeech validates HuggingFace model identifiers", async () => {
  const response = await handleAudioSpeech({
    body: {
      model: "huggingface/../escape",
      input: "bad model",
    },
    credentials: { apiKey: "hf-key" },
  });
  const payload = (await response.json()) as any;

  assert.equal(response.status, 400);
  assert.equal(payload.error.message, "Invalid model ID");
});

test("handleAudioSpeech routes HuggingFace TTS providers to model-specific endpoints", async () => {
  const originalFetch = globalThis.fetch;
  let captured;

  globalThis.fetch = async (url, options = {}) => {
    captured = {
      url: String(url),
      headers: options.headers,
      body: JSON.parse(String(options.body || "{}")),
    };

    return new Response(new Uint8Array([6, 6, 6]), {
      status: 200,
      headers: { "content-type": "audio/wav" },
    });
  };

  try {
    const response = await handleAudioSpeech({
      body: {
        model: "huggingface/facebook/mms-tts-eng",
        input: "hf text",
      },
      credentials: { apiKey: "hf-key" },
    });

    assert.equal(captured.url, "https://api-inference.huggingface.co/models/facebook/mms-tts-eng");
    assert.equal(captured.headers.Authorization, "Bearer hf-key");
    assert.deepEqual(captured.body, { inputs: "hf text" });
    assert.equal(response.status, 200);
  } finally {
    globalThis.fetch = originalFetch;
  }
});

test("handleAudioSpeech maps Inworld requests to basic auth and wav output", async () => {
  const originalFetch = globalThis.fetch;
  let captured;

  globalThis.fetch = async (_url, options = {}) => {
    captured = {
      headers: options.headers,
      body: JSON.parse(String(options.body || "{}")),
    };

    return new Response(JSON.stringify({ audioContent: "AQIDBA==" }), {
      status: 200,
      headers: { "content-type": "application/json" },
    });
  };

  try {
    const response = await handleAudioSpeech({
      body: {
        model: "inworld/inworld-tts-2",
        input: "inworld text",
        voice: "voice-9",
        response_format: "wav",
      },
      credentials: { apiKey: "encoded-basic-token" },
    });

    assert.equal(captured.headers.Authorization, "Basic encoded-basic-token");
    assert.deepEqual(captured.body, {
      text: "inworld text",
      voiceId: "voice-9",
      modelId: "inworld-tts-2",
      audioConfig: { audioEncoding: "WAV" },
    });
    assert.equal(response.headers.get("content-type"), "audio/wav");
    assert.deepEqual(Array.from(new Uint8Array(await response.arrayBuffer())), [1, 2, 3, 4]);
  } finally {
    globalThis.fetch = originalFetch;
  }
});

test("Inworld speech registry exposes supported formats without flac", () => {
  assert.deepEqual(AUDIO_SPEECH_PROVIDERS.inworld.supportedFormats, ["mp3", "wav", "opus", "pcm"]);
});

test("handleAudioSpeech maps Inworld opus output and rejects flac", async () => {
  const originalFetch = globalThis.fetch;
  let captured;
  let callCount = 0;

  globalThis.fetch = async (_url, options = {}) => {
    callCount += 1;
    captured = JSON.parse(String(options.body || "{}"));

    return new Response(JSON.stringify({ audioContent: "BQY=", contentType: "audio/opus" }), {
      status: 200,
      headers: { "content-type": "application/json" },
    });
  };

  try {
    const opusResponse = await handleAudioSpeech({
      body: {
        model: "inworld/inworld-tts-2",
        input: "inworld text",
        response_format: "opus",
      },
      credentials: { apiKey: "encoded-basic-token" },
    });

    assert.deepEqual(captured.audioConfig, { audioEncoding: "OPUS" });
    assert.equal(opusResponse.headers.get("content-type"), "audio/opus");
    assert.deepEqual(Array.from(new Uint8Array(await opusResponse.arrayBuffer())), [5, 6]);

    const flacResponse = await handleAudioSpeech({
      body: {
        model: "inworld/inworld-tts-2",
        input: "inworld text",
        response_format: "flac",
      },
      credentials: { apiKey: "encoded-basic-token" },
    });
    const payload = (await flacResponse.json()) as any;

    assert.equal(flacResponse.status, 400);
    assert.equal(
      payload.error.message,
      "Inworld TTS supports response_format mp3, wav, opus, or pcm only"
    );
    assert.equal(callCount, 1);
  } finally {
    globalThis.fetch = originalFetch;
  }
});

test("handleAudioSpeech supports local Coqui providers without credentials", async () => {
  const originalFetch = globalThis.fetch;
  let captured;

  globalThis.fetch = async (_url, options = {}) => {
    captured = JSON.parse(String(options.body || "{}"));
    return new Response(new Uint8Array([1, 1, 1]), {
      status: 200,
      headers: { "content-type": "audio/wav" },
    });
  };

  try {
    const response = await handleAudioSpeech({
      body: {
        model: "coqui/tts_models/en/ljspeech/tacotron2-DDC",
        input: "coqui text",
        voice: "speaker-a",
      },
      credentials: null,
    });

    assert.deepEqual(captured, { text: "coqui text", speaker_id: "speaker-a" });
    assert.equal(response.status, 200);
  } finally {
    globalThis.fetch = originalFetch;
  }
});

test("handleAudioSpeech supports local Tortoise providers with the default voice", async () => {
  const originalFetch = globalThis.fetch;
  let captured;

  globalThis.fetch = async (_url, options = {}) => {
    captured = JSON.parse(String(options.body || "{}"));
    return new Response(new Uint8Array([2, 2, 2]), {
      status: 200,
      headers: { "content-type": "audio/wav" },
    });
  };

  try {
    const response = await handleAudioSpeech({
      body: {
        model: "tortoise/tortoise-v2",
        input: "tortoise text",
      },
      credentials: null,
    });

    assert.deepEqual(captured, { text: "tortoise text", voice: "random" });
    assert.equal(response.status, 200);
  } finally {
    globalThis.fetch = originalFetch;
  }
});

test("handleAudioSpeech surfaces parsed upstream error messages", async () => {
  const originalFetch = globalThis.fetch;

  globalThis.fetch = async () =>
    new Response(JSON.stringify({ error: { message: "quota exceeded" } }), {
      status: 429,
      headers: { "content-type": "application/json" },
    });

  try {
    const response = await handleAudioSpeech({
      body: {
        model: "openai/tts-1",
        input: "limited text",
      },
      credentials: { apiKey: "openai-key" },
    });
    const payload = (await response.json()) as any;

    assert.equal(response.status, 429);
    assert.equal(payload.error.message, "quota exceeded");
  } finally {
    globalThis.fetch = originalFetch;
  }
});

test("handleAudioSpeech returns a 500 when the provider request throws", async () => {
  const originalFetch = globalThis.fetch;

  globalThis.fetch = async () => {
    throw new Error("socket hang up");
  };

  try {
    const response = await handleAudioSpeech({
      body: {
        model: "openai/tts-1",
        input: "broken request",
      },
      credentials: { apiKey: "openai-key" },
    });
    const payload = (await response.json()) as any;

    assert.equal(response.status, 500);
    assert.equal(payload.error.message, "Speech request failed: socket hang up");
  } finally {
    globalThis.fetch = originalFetch;
  }
});
