import { Buffer } from 'node:buffer';
import { getDb } from '../memory/db.js';
import { env } from '../env.js';

// Lyria 3 is reached via the Gemini "interactions" endpoint (not :predict, which
// is the Vertex path). The clip model returns a ~30s base64 MP3.
const MUSIC_MODEL = process.env.GEMINI_MUSIC_MODEL ?? 'lyria-3-clip-preview';
const INTERACTIONS_URL = 'https://generativelanguage.googleapis.com/v1beta/interactions';

interface PodMusicDoc {
  podId: string;
  name: string; // pod name the vocal was generated for
  model: string;
  mp3Base64: string;
  createdAt: string;
}

interface InteractionContent {
  type?: string;
  data?: string;
  text?: string;
}
interface InteractionResponse {
  steps?: Array<{ content?: InteractionContent[] }>;
  output_audio?: { data?: string };
}

/**
 * Background "hold music" prompt: opens with the pod name sung once, then a calm
 * instrumental bed that loops. Keep it unobtrusive — this is fill, not a song.
 */
function musicPrompt(podName: string): string {
  return [
    'Calm soothing instrumental background hold music for a tech app, like gentle on-hold lobby music.',
    `It opens in the first three seconds with a soft gentle voice clearly saying the words "${podName}" one time,`,
    'and after that opening it is purely instrumental with warm electric piano, gentle synth pads and a soft relaxed beat.',
    'Unobtrusive, pleasant and steady with no climax, designed to loop seamlessly as quiet background fill.',
    'No other lyrics or vocals after the opening.',
  ].join(' ');
}

function extractAudioBase64(data: InteractionResponse): string | null {
  for (const step of data.steps ?? []) {
    for (const c of step.content ?? []) {
      if (c.type === 'audio' && c.data) return c.data;
    }
  }
  return data.output_audio?.data ?? null;
}

async function generate(podName: string): Promise<Buffer> {
  const res = await fetch(INTERACTIONS_URL, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'x-goog-api-key': env.GEMINI_API_KEY },
    body: JSON.stringify({ model: MUSIC_MODEL, input: musicPrompt(podName) }),
  });
  if (!res.ok) {
    throw new Error(`Lyria ${res.status}: ${(await res.text()).slice(0, 300)}`);
  }
  const data = (await res.json()) as InteractionResponse;
  const b64 = extractAudioBase64(data);
  if (!b64) throw new Error('Lyria returned no audio');
  return Buffer.from(b64, 'base64');
}

/**
 * The pod's background-music MP3, generated by Lyria on first request and cached
 * in the `pod_music` collection. Regenerated if the pod name changes so the sung
 * name stays correct. Lyria generation is slow (~20s); the cache makes every
 * call after the first instant.
 */
export async function getPodMusic(podId: string, podName: string): Promise<Buffer> {
  const db = await getDb();
  const col = db.collection<PodMusicDoc>('pod_music');
  const cached = await col.findOne({ podId });
  if (cached && cached.name === podName && cached.model === MUSIC_MODEL && cached.mp3Base64) {
    return Buffer.from(cached.mp3Base64, 'base64');
  }
  const mp3 = await generate(podName);
  await col.updateOne(
    { podId },
    {
      $set: {
        podId,
        name: podName,
        model: MUSIC_MODEL,
        mp3Base64: mp3.toString('base64'),
        createdAt: new Date().toISOString(),
      },
    },
    { upsert: true },
  );
  return mp3;
}
