// ── Integration samples ──────────────────────────────────────────────────

function cleanBaseUrl(url) {
  return String(url || '').trim().replace(/\/+$/, '');
}
function getTtsBaseUrl() {
  return cleanBaseUrl($('s-tts-url')?.value) || 'http://localhost:8020';
}
function getTtsV1Url() {
  const base = getTtsBaseUrl();
  return base.endsWith('/v1') ? base : base + '/v1';
}
function getTtsStreamBaseUrl() {
  return cleanBaseUrl($('s-tts-stream-url')?.value || _appSettings.tts_stream_url) || 'http://localhost:8023';
}
function getTtsStreamV1Url() {
  const base = getTtsStreamBaseUrl();
  return base.endsWith('/v1') ? base : base + '/v1';
}
function getCreatorV1Url() {
  const loc = window.location;
  const protocol = loc.protocol || 'http:';
  const port = loc.port ? ':' + loc.port : '';
  const host = loc.hostname === '0.0.0.0' ? 'localhost' : loc.hostname;
  return `${protocol}//${host}${port}/v1`;
}
function updateCreatorUrlHints() {
  const warning = $('routing-url-warning');
  const badBindHost = window.location.hostname === '0.0.0.0';
  if (warning) warning.classList.toggle('show', badBindHost);
}
function activeVoiceIds() {
  return (_voices || [])
    .filter(v => v.enabled !== false)
    .slice()
    .sort((a, b) => a.id.localeCompare(b.id))
    .map(v => v.id);
}
function integrationVoiceExample() {
  return activeVoiceIds()[0] || 'EN_F_ExampleVoice';
}
function integrationVoiceList() {
  const ids = activeVoiceIds();
  return ids.length ? ids.join(', ') : 'EN_F_ExampleVoice, DE_M_ExampleVoice';
}
function virtualDesignVoiceIds() {
  return Object.keys(loadDesignPresets ? loadDesignPresets() : {})
    .sort((a,b)=>a.localeCompare(b))
    .map(name => 'vd_' + name.replace(/[^A-Za-z0-9_.-]+/g, '_').replace(/^_+|_+$/g, ''));
}
function renderIntegrationSnippets() {
  if (!$('snippet-sillytavern')) return;
  const base = getTtsBaseUrl();
  const v1 = getTtsV1Url();
  const streamV1 = getTtsStreamV1Url();
  const proxyV1 = getCreatorV1Url();
  const proxyBase = proxyV1.replace(/\/v1$/, '');
  updateCreatorUrlHints();
  const voice = integrationVoiceExample();
  const voices = integrationVoiceList();
  const vdVoices = virtualDesignVoiceIds();
  const vdVoice = vdVoices[0] || 'vd_EN_F_Warm_Narrator';
  $('integration-url-label').textContent = 'TTS backend: ' + base;
  $('snippet-sillytavern').textContent =
`Provider: OpenAI compatible TTS
API base URL: ${v1}
API key: dummy
Model: qwen3-tts
Voice: ${voice}
Custom voices: ${voices}

Streaming backend, if your SillyTavern TTS extension supports progressive playback:
API base URL: ${streamV1}
Endpoint: /audio/speech
Format: wav`;
  $('snippet-streaming-howto').textContent =
`Direct streaming backend, no creator routing:
API base URL: ${streamV1}
Endpoint: /audio/speech
Model: tts-1
Voice: ${voice}
Response format: wav
Requirement: the app must start playback while the HTTP response is still arriving.
Current 8023 streaming service ignores per-request instruct/style text.

Streaming through TTS Voice Creator routing:
API base URL: ${proxyV1}
Voice: default or another incoming route voice
Routing tab: set Backend = Streaming for the matching rule
Response format: wav
Avoid before/after sounds for true streaming; route sounds and MP3 require buffering.

SillyTavern note:
Use OpenAI-compatible TTS if your extension supports progressive audio responses. If it waits for the whole file before playing, streaming works technically but will feel like buffered TTS.`;
  $('snippet-open-webui').textContent =
`Admin settings -> Audio -> Text-to-Speech
Engine/provider: OpenAI compatible
API base URL: ${proxyV1}
API key: dummy
Model: tts-1
Voice: default

Routing tab example:
default + EN -> ${voice}
default + DE -> DE_M_YourGermanVoice`;
  $('snippet-home-assistant').textContent =
`Home Assistant OpenAI TTS agent:
Base URL: ${proxyV1}
API key: dummy
Model: tts-1
Voice: default
Extra JSON payload: {"app":"Home Assistant"}
Audio format: mp3 or wav

REST command example using routing:
rest_command:
  routed_tts:
    url: "${proxyV1}/audio/speech"
    method: POST
    content_type: "application/json"
    headers:
      Authorization: "Bearer dummy"
    payload: >
      {"model":"tts-1","voice":"default","input":"{{ text }}","response_format":"mp3","app":"Home Assistant"}

Important: use this Creator proxy URL, not the direct Qwen3 backend URL ${v1}. Routing only runs through the Creator proxy.`;
  $('snippet-curl').textContent =
`curl -s "${v1}/models"

curl -s "${v1}/audio/speech" \\
  -H "Authorization: Bearer dummy" \\
  -H "Content-Type: application/json" \\
  -d '{"model":"qwen3-tts","voice":"${voice}","input":"Hello from Qwen3 TTS","response_format":"wav"}' \\
  --output qwen3-tts-test.wav`;
  $('snippet-voice-design-proxy').textContent =
`Virtual VoiceDesign mode - no WAV export needed

Use this app as the OpenAI-compatible TTS endpoint:
API base URL: ${proxyV1}
API key: dummy
Model: tts-1
Voice: ${vdVoice}

Available virtual voices:
${vdVoices.length ? vdVoices.join(', ') : 'Save a Voice Design prompt preset first.'}

curl -s "${proxyV1}/models"

curl -s "${proxyV1}/audio/speech" \\
  -H "Authorization: Bearer dummy" \\
  -H "Content-Type: application/json" \\
  -d '{"model":"tts-1","voice":"${vdVoice}","input":"This line is generated through the VoiceDesign container.","response_format":"wav"}' \\
  --output voicedesign-virtual.wav`;

  if ($('snippet-mcp-claude-cmd')) $('snippet-mcp-claude-cmd').textContent =
`claude mcp add voice-creator \\
  --transport http \\
  --url ${proxyBase}/mcp \\
  --header "X-Voice-Creator-Client-Id: claude-code"`;

  if ($('snippet-mcp-claude-config')) $('snippet-mcp-claude-config').textContent =
`{
  "mcpServers": {
    "voice-creator": {
      "url": "${proxyBase}/mcp",
      "headers": { "X-Voice-Creator-Client-Id": "my-agent" }
    }
  }
}`;

  if ($('snippet-hotkey')) $('snippet-hotkey').textContent =
`pip install pynput sounddevice soundfile pyperclip requests
python hotkey_daemon.py --server ${proxyBase}`;

  if ($('snippet-speak')) $('snippet-speak').textContent =
`# Bind your client ID to a voice once (persisted in Settings)
curl -X PUT ${proxyBase}/speak/bindings/my-script \\
  -H "Content-Type: application/json" \\
  -d '{"voice":"${voice}"}'

# Generate speech — voice from binding, persona rewrite optional
curl -X POST ${proxyBase}/speak \\
  -H "Content-Type: application/json" \\
  -H "X-Voice-Creator-Client-Id: my-script" \\
  -d '{"text":"Hello world","apply_persona":true}' \\
  --output speech.wav

# Or specify voice directly
curl -X POST ${proxyBase}/speak \\
  -H "Content-Type: application/json" \\
  -d '{"text":"Hello world","voice":"${voice}"}' \\
  --output speech.wav`;

}
document.querySelectorAll('.copy-snippet').forEach(btn => btn.addEventListener('click', async () => {
  const el = $(btn.dataset.snippet);
  if (!el) return;
  await copyText(el.textContent);
  toast('Snippet copied', 'success');
}));
$('show-api-btn')?.addEventListener('click', () => {
  window.open('/docs', '_blank', 'noopener');
});
$('integration-refresh-btn')?.addEventListener('click', () => {
  renderIntegrationSnippets();
  toast('Integration examples refreshed', 'success');
});
$('copy-active-voices-btn-integrations')?.addEventListener('click', async () => {
  const active = activeVoiceIds();
  if (!active.length) { toast('No active voices to copy', 'error'); return; }
  await copyText(active.join(', '));
  toast('Copied ' + active.length + ' active voices', 'success');
  status('Copied active voices to clipboard');
});

