// VoiceOutput — speaker button that reads text aloud via the browser's
// SpeechSynthesis API. Same shape as main project's voice-output.tsx,
// ported to the MVP's no-Tailwind / no-framer-motion stack.
//
// Props:
//   text       — string to speak. Markdown is stripped before TTS.
//   autoPlay?  — speak the text once when it first appears (used for the
//                voice-in → voice-out chat flow).

const _VOIcon = ({ d, size = 14 }) => (
  <svg width={size} height={size} viewBox="0 0 24 24" fill="none" stroke="currentColor"
       strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
    {typeof d === 'string' ? <path d={d}/> : d}
  </svg>
);
const IconSpeaker = (p) => <_VOIcon {...p} d={<><path d="M11 5L6 9H2v6h4l5 4V5z"/><path d="M15.54 8.46a5 5 0 0 1 0 7.07"/><path d="M19.07 4.93a10 10 0 0 1 0 14.14"/></>}/>;
const IconStop2   = (p) => <_VOIcon {...p} d={<rect x="6" y="6" width="12" height="12" rx="1"/>}/>;

// Strip markdown so speech sounds natural (no "asterisk asterisk bold").
function _stripMd(md) {
  return String(md || '')
    .replace(/```[\s\S]*?```/g, ' ')
    .replace(/`([^`]+)`/g, '$1')
    .replace(/!\[[^\]]*\]\([^)]+\)/g, ' ')
    .replace(/\[([^\]]+)\]\([^)]+\)/g, '$1')
    .replace(/^#{1,6}\s+/gm, '')
    .replace(/\*\*([^*]+)\*\*/g, '$1')
    .replace(/\*([^*]+)\*/g, '$1')
    .replace(/__([^_]+)__/g, '$1')
    .replace(/_([^_]+)_/g, '$1')
    .replace(/^\s*[-*+]\s+/gm, '')
    .replace(/^\s*\d+\.\s+/gm, '')
    .replace(/\|/g, ' ')
    .replace(/---+/g, ' ')
    .replace(/\s+/g, ' ')
    .trim();
}

// Pick the best installed voice for a BCP-47 code (exact match first, then
// base language, e.g. "ta-IN" → fall back to any "ta-*" voice).
function _pickVoice(code) {
  if (typeof window === 'undefined' || !window.speechSynthesis) return null;
  const voices = window.speechSynthesis.getVoices();
  if (!voices.length) return null;
  const exact = voices.find(v => v.lang && v.lang.toLowerCase() === code.toLowerCase());
  if (exact) return exact;
  const base = code.split('-')[0].toLowerCase();
  return voices.find(v => v.lang && v.lang.toLowerCase().startsWith(base)) || null;
}

const VoiceOutput = ({ text, autoPlay = false }) => {
  const lang = window.useLanguage();
  const t = lang.t;
  const [speaking, setSpeaking] = React.useState(false);
  const utterRef = React.useRef(null);
  const autoPlayedRef = React.useRef(false);

  const supported = typeof window !== 'undefined' && 'speechSynthesis' in window;

  // Voices load asynchronously in some browsers (Chrome). Force load on mount
  // and listen for the voiceschanged event.
  React.useEffect(() => {
    if (!supported) return;
    window.speechSynthesis.getVoices(); // trigger
    const onChange = () => window.speechSynthesis.getVoices();
    window.speechSynthesis.onvoiceschanged = onChange;
    return () => { try { window.speechSynthesis.onvoiceschanged = null; } catch {} };
  }, [supported]);

  const stop = () => {
    if (!supported) return;
    window.speechSynthesis.cancel();
    setSpeaking(false);
    utterRef.current = null;
  };

  const speak = React.useCallback(() => {
    if (!supported) return;
    const clean = _stripMd(text);
    if (!clean) return;
    window.speechSynthesis.cancel(); // never overlap

    const code = (lang.current && lang.current.speechCode) || 'en-US';
    const utter = new SpeechSynthesisUtterance(clean);
    utter.lang = code;
    const v = _pickVoice(code);
    if (v) utter.voice = v;
    utter.rate = 1.0;
    utter.pitch = 1.0;
    utter.onstart = () => setSpeaking(true);
    utter.onend   = () => { setSpeaking(false); utterRef.current = null; };
    utter.onerror = () => { setSpeaking(false); utterRef.current = null; };

    utterRef.current = utter;

    if (!window.speechSynthesis.getVoices().length) {
      // Voices not loaded yet — wait briefly then speak.
      setTimeout(() => {
        const v2 = _pickVoice(code);
        if (v2) utter.voice = v2;
        window.speechSynthesis.speak(utter);
      }, 250);
      return;
    }
    window.speechSynthesis.speak(utter);
  }, [text, lang, supported]);

  const toggle = () => { if (speaking) stop(); else speak(); };

  // Auto-play once per text change when enabled.
  React.useEffect(() => {
    if (autoPlay && !autoPlayedRef.current && text) {
      autoPlayedRef.current = true;
      const id = setTimeout(speak, 200);
      return () => clearTimeout(id);
    }
  }, [autoPlay, text, speak]);

  // Cancel speech on unmount.
  React.useEffect(() => () => {
    if (utterRef.current && supported) {
      try { window.speechSynthesis.cancel(); } catch {}
    }
  }, [supported]);

  if (!supported) return null;

  return (
    <button
      type="button"
      onClick={toggle}
      title={speaking ? t('Stop') : t('Read aloud')}
      data-voice-output="1"
      style={{
        background: speaking ? 'rgba(99,102,241,0.12)' : 'transparent',
        color: speaking ? '#6366f1' : 'var(--fg-3)',
        border: 'none', cursor: 'pointer',
        padding: 4, borderRadius: 4,
        display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
        verticalAlign: 'middle', marginLeft: 6,
      }}
    >
      {speaking ? <IconStop2 size={12}/> : <IconSpeaker size={12}/>}
    </button>
  );
};

window.VoiceOutput = VoiceOutput;
