import { NextResponse } from "next/server";
import { Communicate } from "edge-tts-ts";

export const runtime = "nodejs";
export const dynamic = "force-dynamic";

const DEFAULT_VOICE = process.env.EDGE_TTS_VOICE || "zh-CN-XiaoxiaoNeural";
const MAX_TEXT_LENGTH = 12000;

type EdgeTtsRequest = {
  text?: unknown;
  voice?: unknown;
};

const jsonError = (message: string, status: number) =>
  NextResponse.json({ error: message }, { status });

export async function POST(request: Request) {
  let payload: EdgeTtsRequest;
  try {
    payload = (await request.json()) as EdgeTtsRequest;
  } catch {
    return jsonError("Invalid JSON body", 400);
  }

  const text = typeof payload.text === "string" ? payload.text.trim() : "";
  if (!text) {
    return jsonError("text is required", 400);
  }
  if (text.length > MAX_TEXT_LENGTH) {
    return jsonError(`text must be ${MAX_TEXT_LENGTH} characters or fewer`, 413);
  }

  const voice =
    typeof payload.voice === "string" && payload.voice.trim()
      ? payload.voice.trim()
      : DEFAULT_VOICE;

  try {
    const communicate = new Communicate(text, { voice });
    const chunks: Uint8Array[] = [];
    let byteLength = 0;

    for await (const chunk of communicate.stream()) {
      if (chunk.type !== "audio") continue;
      chunks.push(chunk.data);
      byteLength += chunk.data.byteLength;
    }

    if (byteLength === 0) {
      return jsonError("Edge TTS returned empty audio", 502);
    }

    const audio = new Uint8Array(byteLength);
    let offset = 0;
    for (const chunk of chunks) {
      audio.set(chunk, offset);
      offset += chunk.byteLength;
    }

    const audioBuffer = audio.buffer.slice(
      audio.byteOffset,
      audio.byteOffset + audio.byteLength,
    );

    return new Response(audioBuffer, {
      headers: {
        "Content-Type": "audio/mpeg",
        "Cache-Control": "no-store",
      },
    });
  } catch (error) {
    console.error("[EdgeTTS] Failed to synthesize speech:", error);
    return jsonError("Failed to synthesize speech", 502);
  }
}
