// ── STT -> TTS ───────────────────────────────────────────────────────────

let sttTtsSourceId = null;
let sttTtsOutputBlob = null;
let _sttBackends = [];
let sttTtsRecorder = null;
let sttTtsRecordStream = null;
let sttTtsRecordChunks = [];
let sttTtsRecordTimer = null;
let sttTtsRecordSecs = 0;

function sttTtsSelectedSttBackend() {
  return $('stt-tts-stt-backend')?.value || 'configured';
}

function sttBackendOptionHtml(selected = 'configured') {
  if (!_sttBackends.length) return '<option value="configured">Configured Whisper/STT</option>';
  const preferred = _sttBackends.some(b => b.id === selected && b.available) ? selected : (_sttBackends.find(b => b.available)?.id || selected);
  return _sttBackends.map(b => {
    const suffix = b.available ? '' : ' (unavailable)';
    const disabled = b.available ? '' : ' disabled';
    return `<option value="${escHtml(b.id)}" ${b.id === preferred ? 'selected' : ''}${disabled}>${escHtml(b.label + suffix)}</option>`;
  }).join('');
}

function updateSttBackendHelp() {
  const selected = sttTtsSelectedSttBackend();
  const b = _sttBackends.find(item => item.id === selected) || _sttBackends.find(item => item.available) || null;
  const help = $('stt-tts-stt-help');
  if (!help) return;
  if (!b) { help.textContent = 'No STT engine status loaded yet.'; return; }
  help.innerHTML = sttBackendHelpHtml(b);
}

async function refreshSttBackends(selected = '') {
  try {
    const d = await fetch('/api/stt-backends').then(r => r.json());
    _sttBackends = (d.backends || []).filter(b => b && b.id);
  } catch (_) {
    _sttBackends = [];
  }
  ['stt-tts-stt-backend', 'clone-stt-backend'].forEach(id => {
    const sel = $(id);
    if (!sel) return;
    const prev = selected || sel.value || 'configured';
    sel.innerHTML = sttBackendOptionHtml(prev);
    sel.disabled = !_sttBackends.some(b => b.available);
  });
  updateSttBackendHelp();
}

function sttTtsSelectedBackend() {
  return $('stt-tts-backend-select')?.value || '';
}

function sttTtsDownload(blob, name) {
  if (!blob) return;
  const a = document.createElement('a');
  a.href = URL.createObjectURL(blob);
  a.download = name;
  a.click();
}

async function sttTtsUploadFile(file) {
  if (!file) return;
  $('stt-tts-source-status').textContent = 'Uploading ' + file.name + '...';
  sttTtsSourceId = null;
  sttTtsOutputBlob = null;
  $('stt-tts-transcribe-btn').disabled = true;
  $('stt-tts-copy-preview-btn').disabled = true;
  $('stt-tts-save-mp3-btn').disabled = true;
  $('stt-tts-save-wav-btn').disabled = true;
  const fd = new FormData();
  fd.append('file', file);
  try {
    const r = await fetch('/api/upload', {method:'POST', body:fd});
    if (!r.ok) { const e = await r.json().catch(()=>({})); throw new Error(e.detail || r.statusText); }
    const d = await r.json();
    sttTtsSourceId = d.id;
    const audio = $('stt-tts-source-audio');
    audio.src = '/api/audio/' + encodeURIComponent(d.id);
    audio.style.display = '';
    $('stt-tts-source-status').textContent = `${d.filename || file.name} loaded (${Number(d.duration || 0).toFixed(1)} s).`;
    $('stt-tts-transcribe-btn').disabled = false;
    toast('Speech audio loaded', 'success');
  } catch (e) {
    $('stt-tts-source-status').textContent = 'Upload failed.';
    toast('STT source upload failed: ' + e.message, 'error');
  }
}

async function sttTtsFetchVoices() {
  const backend = sttTtsSelectedBackend();
  if (!backend) throw new Error('No available TTS backend');
  const rawVoices = await fetch('/api/tts-voices?backend=' + encodeURIComponent(backend)).then(r => r.json());
  let voices = Array.isArray(rawVoices) ? rawVoices : [];
  if (shouldFilterBackendVoices(backend)) {
    const activeIds = await activeLibraryVoiceIds();
    voices = voices.filter(v => activeIds.has(backendVoiceId(v)));
  }
  const sel = $('stt-tts-voice-select'), prev = sel.value;
  sel.innerHTML = '<option value="">-- select after fetch --</option>';
  voices.forEach(v => {
    const id = backendVoiceId(v);
    const opt = document.createElement('option');
    opt.value = opt.textContent = id;
    sel.appendChild(opt);
  });
  if (prev && voices.some(v => backendVoiceId(v) === prev)) sel.value = prev;
  return voices.length;
}

$('stt-tts-file')?.addEventListener('change', async () => {
  const input = $('stt-tts-file');
  if (input.files && input.files.length) await sttTtsUploadFile(input.files[0]);
  input.value = '';
});
$('stt-tts-refresh-stt-btn')?.addEventListener('click', async () => {
  const btn = $('stt-tts-refresh-stt-btn');
  btn.disabled = true;
  try {
    await refreshSttBackends(sttTtsSelectedSttBackend());
    toast('STT engines refreshed', 'success');
  } finally {
    btn.disabled = false;
  }
});
$('stt-tts-stt-backend')?.addEventListener('change', updateSttBackendHelp);

function sttTtsSetRecording(on) {
  $('stt-tts-rec-start').disabled = on;
  $('stt-tts-rec-stop').disabled = !on;
}

function sttTtsStopTracks() {
  if (sttTtsRecordStream) sttTtsRecordStream.getTracks().forEach(t => t.stop());
  sttTtsRecordStream = null;
}

$('stt-tts-rec-start')?.addEventListener('click', async () => {
  try {
    sttTtsRecordStream = await requestMicrophoneStream();
    sttTtsRecordChunks = [];
    sttTtsRecordSecs = 0;
    $('stt-tts-rec-time').textContent = '0:00';
    $('stt-tts-source-status').textContent = 'Recording...';
    sttTtsSetRecording(true);
    sttTtsRecordTimer = setInterval(() => {
      sttTtsRecordSecs++;
      $('stt-tts-rec-time').textContent = Math.floor(sttTtsRecordSecs / 60) + ':' + String(sttTtsRecordSecs % 60).padStart(2, '0');
    }, 1000);
    sttTtsRecorder = new MediaRecorder(sttTtsRecordStream, {audioBitsPerSecond: 256000});
    sttTtsRecorder.ondataavailable = e => { if (e.data.size) sttTtsRecordChunks.push(e.data); };
    sttTtsRecorder.onstop = async () => {
      clearInterval(sttTtsRecordTimer);
      sttTtsRecordTimer = null;
      sttTtsSetRecording(false);
      sttTtsStopTracks();
      const mime = sttTtsRecorder.mimeType || 'audio/webm';
      const blob = new Blob(sttTtsRecordChunks, {type:mime});
      const ext = mime.includes('ogg') ? '.ogg' : '.webm';
      if (!blob.size) {
        $('stt-tts-source-status').textContent = 'Recording was empty.';
        toast('Recording was empty', 'error');
        return;
      }
      await sttTtsUploadFile(new File([blob], 'stt-recording' + ext, {type:mime}));
    };
    sttTtsRecorder.start(100);
    toast('Recording started', 'success');
  } catch (e) {
    sttTtsSetRecording(false);
    sttTtsStopTracks();
    const message = await microphoneErrorMessage(e);
    $('stt-tts-source-status').textContent = message;
    toast(message, 'error');
  }
});

$('stt-tts-rec-stop')?.addEventListener('click', () => {
  if (sttTtsRecorder && sttTtsRecorder.state !== 'inactive') sttTtsRecorder.stop();
});

$('stt-tts-transcribe-btn')?.addEventListener('click', async () => {
  if (!sttTtsSourceId) { toast('Load speech audio first', 'error'); return; }
  const btn = $('stt-tts-transcribe-btn');
  btn.disabled = true;
  $('stt-tts-source-status').textContent = 'Transcribing...';
  try {
    const r = await fetch('/api/transcribe', {method:'POST', headers:{'Content-Type':'application/json'}, body:JSON.stringify({id:sttTtsSourceId, backend:sttTtsSelectedSttBackend()})});
    if (!r.ok) { const e = await r.json().catch(()=>({})); throw new Error(e.detail || r.statusText); }
    const d = await r.json();
    $('stt-tts-text').value = d.text || '';
    $('stt-tts-copy-preview-btn').disabled = !(d.text || '').trim();
    const used = d.backend ? ' via ' + d.backend : '';
    $('stt-tts-source-status').textContent = 'Transcription ready' + used + '.';
    if (typeof updateRefineButtonState === 'function') updateRefineButtonState();
    toast('Transcription ready', 'success');
  } catch (e) {
    $('stt-tts-source-status').textContent = 'Transcription failed.';
    toast('STT failed: ' + e.message, 'error');
  } finally {
    btn.disabled = false;
  }
});

$('stt-tts-copy-preview-btn')?.addEventListener('click', () => {
  const text = $('stt-tts-text').value.trim();
  if (!text) return;
  $('preview-text-area').value = text;
  switchTab('generation');
  toast('Copied transcription to TTS Generation', 'success');
});

$('stt-tts-backend-select')?.addEventListener('change', () => {
  $('stt-tts-voice-select').innerHTML = '<option value="">-- select after fetch --</option>';
  sttTtsOutputBlob = null;
  $('stt-tts-save-mp3-btn').disabled = true;
  $('stt-tts-save-wav-btn').disabled = true;
  updateBackendHelp();
});

$('stt-tts-fetch-voices-btn')?.addEventListener('click', async () => {
  const btn = $('stt-tts-fetch-voices-btn');
  btn.disabled = true;
  try {
    const count = await sttTtsFetchVoices();
    toast('Fetched ' + count + ' voices', 'success');
  } catch (e) {
    toast('Fetch failed: ' + e.message, 'error');
  } finally {
    btn.disabled = false;
  }
});

$('stt-tts-generate-btn')?.addEventListener('click', async () => {
  const backend = sttTtsSelectedBackend();
  const voice = $('stt-tts-voice-select').value;
  const text = $('stt-tts-text').value.trim();
  const instruct = $('stt-tts-style-instruction').value.trim();
  if (!backend) { toast('No available TTS backend', 'error'); return; }
  if (!voice) { toast('Select a TTS voice', 'error'); return; }
  if (!text) { toast('Transcribe or enter text first', 'error'); return; }
  const btn = $('stt-tts-generate-btn');
  btn.disabled = true;
  $('stt-tts-save-mp3-btn').disabled = true;
  $('stt-tts-save-wav-btn').disabled = true;
  try {
    const source = await createTtsAudioSource(voice, text, backend, $('stt-tts-playback-mode').value, instruct);
    sttTtsOutputBlob = source.blob;
    const audio = $('stt-tts-output-audio');
    audio.src = source.url;
    audio.style.display = '';
    await audio.play();
    $('stt-tts-save-mp3-btn').disabled = false;
    $('stt-tts-save-wav-btn').disabled = source.streaming;
    toast(source.streaming ? 'Streaming synthesized speech' : 'Synthesized speech ready', 'success');
  } catch (e) {
    toast('TTS failed: ' + e.message, 'error');
  } finally {
    btn.disabled = false;
  }
});

$('stt-tts-save-mp3-btn')?.addEventListener('click', async () => {
  const backend = sttTtsSelectedBackend();
  const voice = $('stt-tts-voice-select').value;
  const text = $('stt-tts-text').value.trim();
  const instruct = $('stt-tts-style-instruction').value.trim();
  if (!backend || !voice || !text) return;
  const btn = $('stt-tts-save-mp3-btn');
  btn.disabled = true;
  try {
    const blob = await fetchTtsPreviewBlob(voice, text, 'mp3', instruct, backend);
    sttTtsDownload(blob, (voice || 'stt_tts') + '_stt_tts.mp3');
    toast('MP3 saved', 'success');
  } catch (e) {
    toast('MP3 save failed: ' + e.message, 'error');
  } finally {
    btn.disabled = false;
  }
});

$('stt-tts-save-wav-btn')?.addEventListener('click', () => {
  if (!sttTtsOutputBlob) return;
  sttTtsDownload(sttTtsOutputBlob, ($('stt-tts-voice-select').value || 'stt_tts') + '_stt_tts.wav');
});


