import { getVoiceClientConfig } from '@server/services/ai-providers.service';
import { resolveApiKey } from '@server/services/provider-keys.service';

export interface TtsResult {
  audioBuffer: Buffer;
  contentType: string;
}

const NO_KEY_MSG = 'No TTS API key configured — add your OpenAI key in Restaurant Settings → AI Keys.';

export async function synthesizeSpeech(
  text: string,
  voiceModelId: string | null,
  restaurantId?: string | null,
  overrideLanguageCode?: string | null
): Promise<TtsResult> {
  if (!voiceModelId) {
    const key = await resolveApiKey(restaurantId || null, 'openai');
    return synthesizeOpenAI(text, 'nova', key || undefined);
  }

  const config = await getVoiceClientConfig(voiceModelId, restaurantId);

  if (config.providerName === 'openai_realtime') {
    const openaiKey = config.apiKey || (restaurantId ? await resolveApiKey(restaurantId, 'openai') : null) || process.env.OPENAI_API_KEY;
    return synthesizeOpenAI(text, config.voiceId, openaiKey || undefined);
  }

  // Always resolve a fresh OpenAI key in the fallthrough; if the provider is non-OpenAI (e.g.
  // a legacy Sarvam voice model still in the DB), use 'nova' so no invalid speaker IDs are
  // forwarded to the OpenAI TTS endpoint.
  const openaiKey = (restaurantId ? await resolveApiKey(restaurantId, 'openai') : null) || process.env.OPENAI_API_KEY;
  const isOpenAIProvider = config.providerName.startsWith('openai');
  return synthesizeOpenAI(text, isOpenAIProvider ? config.voiceId : 'nova', openaiKey || undefined);
}

async function synthesizeOpenAI(
  text: string,
  voiceId: string,
  apiKey: string | undefined
): Promise<TtsResult> {
  const key = apiKey || process.env.OPENAI_API_KEY;
  if (!key) {
    throw new Error(NO_KEY_MSG);
  }

  const res = await fetch('https://api.openai.com/v1/audio/speech', {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${key}`,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      model: 'tts-1',
      input: text,
      voice: voiceId || 'nova',
      response_format: 'wav',
    }),
  });

  if (!res.ok) {
    if (res.status === 401 || res.status === 403) {
      throw new Error(NO_KEY_MSG);
    }
    const errText = await res.text();
    let detail: string;
    try {
      const parsed = JSON.parse(errText) as { error?: { message?: string } };
      detail = parsed?.error?.message || errText;
    } catch {
      detail = errText;
    }
    throw new Error(`OpenAI TTS ${res.status}: ${detail}`);
  }

  const arrayBuf = await res.arrayBuffer();
  return { audioBuffer: Buffer.from(arrayBuf), contentType: 'audio/wav' };
}
