#!/usr/bin/env node

const baseURL = (process.env.GATEWAY_BASE_URL || 'http://localhost:8080').replace(/\/+$/, '');
const apiKey = process.env.GATEWAY_API_KEY || process.env.EASYAI_GATEWAY_API_KEY;
const cloneModel = process.env.GATEWAY_VOICE_CLONE_MODEL || 'MiniMax-Voice-Clone';
const speechModel = process.env.GATEWAY_TTS_MODEL || 'speech-2.6-turbo';
const voiceId =
  process.env.VOICE_CLONE_ID || `voice_clone_${Date.now().toString(36)}`;
const audioURL =
  process.env.VOICE_CLONE_AUDIO_URL ||
  `${baseURL}/static/simulation/audio.wav`;
const marker = `voice-clone-e2e-${Date.now().toString(36)}`;

if (!apiKey) {
  throw new Error('Set GATEWAY_API_KEY or EASYAI_GATEWAY_API_KEY');
}

function assert(condition, message) {
  if (!condition) throw new Error(message);
}

async function request(path, init = {}) {
  const res = await fetch(`${baseURL}${path}`, {
    ...init,
    headers: {
      Authorization: `Bearer ${apiKey}`,
      'Content-Type': 'application/json',
      ...(init.headers || {}),
    },
  });
  const text = await res.text();
  const body = text ? JSON.parse(text) : {};
  if (!res.ok) {
    throw new Error(`${init.method || 'GET'} ${path} failed ${res.status}: ${text}`);
  }
  return body;
}

async function postAsyncTask(path, body) {
  const accepted = await request(path, {
    method: 'POST',
    headers: { 'X-Async': 'true' },
    body: JSON.stringify(body),
  });
  const taskId = accepted.taskId || accepted.task?.id;
  assert(taskId, `Expected async task id from ${path}`);
  return pollTask(taskId);
}

async function pollTask(taskId, timeoutMs = 120000) {
  const started = Date.now();
  while (Date.now() - started < timeoutMs) {
    const task = await request(`/api/v1/tasks/${taskId}`);
    if (task.status === 'succeeded') return task;
    if (task.status === 'failed') {
      throw new Error(`Task ${taskId} failed: ${task.errorMessage || task.error || JSON.stringify(task)}`);
    }
    await new Promise((resolve) => setTimeout(resolve, 1000));
  }
  throw new Error(`Timed out waiting for task ${taskId}`);
}

const cloneTask = await postAsyncTask('/v1/voice_clone', {
  model: cloneModel,
  voice_id: voiceId,
  audio_url: audioURL,
  text: 'hello voice clone preview',
  preview_model: process.env.VOICE_CLONE_PREVIEW_MODEL || 'speech-2.8-hd',
  runMode: 'simulation',
  simulation: true,
  integrationTestMarker: `${marker}-clone`,
});

const cloneResult = cloneTask.result || {};
const clonedVoice = cloneResult.cloned_voice || cloneResult.clonedVoice;
assert(cloneResult.status === 'success', `Unexpected clone result: ${JSON.stringify(cloneResult)}`);
assert((cloneResult.voice_id || clonedVoice?.voiceId || clonedVoice?.voice_id) === voiceId, 'Clone voice_id mismatch');
assert(clonedVoice?.platformId || clonedVoice?.platform_id, 'Clone result missing platform binding');

const listResult = await request('/v1/voice_clone/voices');
const voices = listResult.items || listResult.data || [];
const listedVoice = voices.find((item) => item.voiceId === voiceId || item.voice_id === voiceId);
assert(listedVoice, 'Cloned voice is missing from voice list');
assert(
  (listedVoice.platformId || listedVoice.platform_id) ===
    (clonedVoice.platformId || clonedVoice.platform_id),
  'Listed voice platform binding mismatch',
);

const speechTask = await postAsyncTask('/v1/speech/generations', {
  model: speechModel,
  text: 'hello from cloned voice',
  cloned_voice_id: clonedVoice.id,
  runMode: 'simulation',
  simulation: true,
  integrationTestMarker: `${marker}-speech`,
});
const speechResult = speechTask.result || {};
assert(speechResult.status === 'success', `Unexpected speech result: ${JSON.stringify(speechResult)}`);
const speechAttemptPlatformId = speechTask.attempts?.[0]?.platformId;
assert(speechAttemptPlatformId, 'Speech task is missing attempt platformId');
assert(
  speechAttemptPlatformId === (clonedVoice.platformId || clonedVoice.platform_id),
  `Speech used ${speechAttemptPlatformId}, expected cloned voice platform ${clonedVoice.platformId || clonedVoice.platform_id}`,
);

if (process.env.GATEWAY_CROSS_PLATFORM_TTS_MODEL) {
  try {
    await postAsyncTask('/v1/speech/generations', {
      model: process.env.GATEWAY_CROSS_PLATFORM_TTS_MODEL,
      text: 'this should not cross platform',
      cloned_voice_id: clonedVoice.id,
      runMode: 'simulation',
      simulation: true,
    });
    throw new Error('Cross-platform TTS request unexpectedly succeeded');
  } catch (error) {
    if (String(error?.message || '').includes('unexpectedly succeeded')) throw error;
  }
}

console.log(
  JSON.stringify(
    {
      ok: true,
      voiceId,
      clonedVoiceId: clonedVoice.id,
      platformId: clonedVoice.platformId || clonedVoice.platform_id,
      cloneTaskId: cloneTask.id,
      speechTaskId: speechTask.id,
    },
    null,
    2,
  ),
);
