// Voice provider abstraction.
//
// Today the Jarvis UI can dispatch over four lanes:
//   - openai_realtime   — primary, WebRTC duplex (lib/realtime-openai.js)
//   - anthropic_stream  — fallback, existing typed-chat /api/orchestrator/command
//   - openai_tts        — TTS-only playback path (lib/tts.js)
//   - elevenlabs_tts    — TTS-only playback path (lib/tts.js)
//   - local_stt / local_tts — env-driven slots for self-hosted Whisper/Piper-style
//                              servers. We never spawn local binaries from here;
//                              the slot is a URL the front-end may hit when set.
//
// This module is pure: it never makes a network call. It reads vault keys via
// `getSecret` (with the existing process.env migration fallback) and reports
// which lanes are usable. The Jarvis UI uses this to pick a default mode and
// to surface provider chips. Every lane stays fully optional — no key is ever
// committed and missing keys downgrade gracefully.

import { getSecret } from '../secrets.js';

export const VOICE_MODES = ['realtime', 'tts', 'local', 'off'];
export const REALTIME_PROVIDERS = ['openai'];
export const TTS_PROVIDERS = ['openai', 'elevenlabs', 'local'];
export const STT_PROVIDERS = ['openai', 'elevenlabs', 'local'];

function hasSecret(name) {
  return Boolean(getSecret(name) || process.env[name]);
}

function localUrl(name) {
  const value = process.env[name];
  return value && /^https?:\/\//i.test(value.trim()) ? value.trim() : null;
}

export function getVoiceCapabilities() {
  const realtime = {
    openai: hasSecret('OPENAI_API_KEY'),
  };
  const tts = {
    openai: hasSecret('OPENAI_API_KEY'),
    elevenlabs: hasSecret('ELEVENLABS_API_KEY'),
    local: Boolean(localUrl('MADARX_LOCAL_TTS_URL')),
  };
  const stt = {
    openai: hasSecret('OPENAI_API_KEY'),
    elevenlabs: hasSecret('ELEVENLABS_API_KEY'),
    local: Boolean(localUrl('MADARX_LOCAL_STT_URL')) || process.env.LOCAL_WHISPER === '1',
  };
  const llm = {
    anthropic: hasSecret('ANTHROPIC_API_KEY'),
    openai: hasSecret('OPENAI_API_KEY'),
  };
  return { realtime, tts, stt, llm };
}

export function pickDefaultMode(caps = getVoiceCapabilities()) {
  if (caps.realtime.openai) return 'realtime';
  if (caps.tts.openai || caps.tts.elevenlabs || caps.tts.local) return 'tts';
  if (caps.stt.local && caps.tts.local) return 'local';
  return 'off';
}

export function pickDefaultTtsProvider(caps = getVoiceCapabilities()) {
  const preferred = String(process.env.MADARX_VOICE_DEFAULT_PROVIDER || '').toLowerCase();
  if (preferred && caps.tts[preferred]) return preferred;
  if (caps.tts.elevenlabs) return 'elevenlabs';
  if (caps.tts.openai) return 'openai';
  if (caps.tts.local) return 'local';
  return null;
}

export function getLocalSlots() {
  return {
    tts_url: localUrl('MADARX_LOCAL_TTS_URL'),
    stt_url: localUrl('MADARX_LOCAL_STT_URL'),
  };
}

export function summarizeProviders(caps = getVoiceCapabilities()) {
  const flags = [];
  if (caps.realtime.openai) flags.push('openai_realtime');
  if (caps.llm.anthropic) flags.push('anthropic_stream');
  if (caps.tts.openai) flags.push('openai_tts');
  if (caps.tts.elevenlabs) flags.push('elevenlabs_tts');
  if (caps.stt.elevenlabs) flags.push('elevenlabs_scribe');
  if (caps.stt.local) flags.push('local_stt');
  if (caps.tts.local) flags.push('local_tts');
  return flags;
}

export function listVoiceProviders() {
  const caps = getVoiceCapabilities();
  return {
    capabilities: caps,
    default_mode: pickDefaultMode(caps),
    default_tts_provider: pickDefaultTtsProvider(caps),
    providers_configured: summarizeProviders(caps),
    local_slots: getLocalSlots(),
  };
}
