/**
 * components/voice.jsx
 *
 * VoiceChat — thin shell composing sub-components.
 * Depends on globals from voice_schemas.jsx and voice_engine.jsx
 * (setVoiceCredentials, processVoiceInput, matchDSL, executeDSL).
 */

// ── Styles (shared constant) ────────────────────────────────

const _VS = {
  container: { padding: '12px', fontFamily: '"JetBrains Mono", monospace', maxWidth: '600px' },
  header: { display: 'flex', alignItems: 'center', gap: '6px', marginBottom: '10px', flexWrap: 'wrap' },
  title: { fontWeight: 'bold', fontSize: '13px', color: '#111' },
  select: { fontSize: '11px', padding: '2px 4px', background: '#fff', color: '#111', border: '1px solid #ddd', borderRadius: '3px' },
  toggleLabel: { fontSize: '11px', display: 'flex', gap: '4px', alignItems: 'center', color: '#555', cursor: 'pointer' },
  clearBtn: { fontSize: '11px', padding: '2px 8px', background: '#fff', color: '#555', border: '1px solid #ddd', borderRadius: '3px', cursor: 'pointer', marginLeft: 'auto' },
  micBtn: { display: 'block', margin: '0 auto 8px', width: '72px', height: '72px', borderRadius: '50%', border: 'none', cursor: 'pointer', fontSize: '28px', color: '#fff', transition: 'background 0.3s, transform 0.1s' },
  stateLabel: { textAlign: 'center', fontSize: '12px', marginBottom: '4px' },
  hint: { textAlign: 'center', fontSize: '10px', color: '#666', marginBottom: '10px' },
  error: { background: '#fee2e2', border: '1px solid #fecaca', borderRadius: '10px', padding: '8px 10px', color: '#b91c1c', fontSize: '12px', marginBottom: '6px' },
  chipBtn: { fontSize: '10px', padding: '3px 8px', background: '#fff', color: '#555', border: '1px solid #ddd', borderRadius: '12px', cursor: 'pointer' },
  historyBox: { marginTop: '8px', maxHeight: '120px', overflowY: 'auto', background: '#fff', border: '1px solid #eee', borderRadius: '10px', padding: '6px 8px' },
};

function _bubbleStyle(role) {
  return {
    background: role === 'user' ? '#eef2ff' : '#f3f4f6',
    border: `1px solid ${role === 'user' ? '#c7d2fe' : '#e5e7eb'}`,
    borderRadius: '10px', padding: '10px 12px', fontSize: '13px',
    marginBottom: '6px', color: '#111827', lineHeight: '1.5',
  };
}

function _roleLabelStyle(role) {
  return { color: role === 'user' ? '#4338ca' : '#065f46', fontWeight: 'bold' };
}

const _STATE_CONFIG = {
  idle: { label: 'Nacisnij aby mowic', color: '#444', icon: '🎤' },
  listening: { label: 'Slucham...', color: '#e74c3c', icon: '⏹' },
  thinking: { label: 'Dzialem...', color: '#f39c12', icon: '⏳' },
  speaking: { label: 'Mowie...', color: '#27ae60', icon: '🔊' },
};

// ── VoiceHeader — settings bar ──────────────────────────────

function VoiceHeader({ model, lang, ttsEnabled, onModel, onLang, onTts, onClear, hasSR, hasTTS }) {
  const h = React.createElement;
  return h('div', { style: _VS.header },
    h('span', { style: _VS.title }, 'Glos AI'),
    h('span', { style: { fontSize: '10px', color: '#555', marginRight: 'auto' } },
      'Web Speech API  STT ' + (hasSR ? 'v' : 'x') + '  TTS ' + (hasTTS ? 'v' : 'x'),
    ),
    h('select', { value: model, onChange: e => onModel(e.target.value), style: _VS.select },
      [['cheap','cheap (Haiku)'],['balanced','balanced (Sonnet)'],['free','free (Gemini)'],['local','local (Ollama)'],['premium','premium (Opus)']]
        .map(([v,l]) => h('option', { key: v, value: v }, l))
    ),
    h('select', { value: lang, onChange: e => onLang(e.target.value), style: _VS.select },
      [['pl-PL','Polski'],['en-US','English'],['de-DE','Deutsch']]
        .map(([v,l]) => h('option', { key: v, value: v }, l))
    ),
    h('label', { style: _VS.toggleLabel },
      h('input', { type: 'checkbox', checked: ttsEnabled, onChange: e => onTts(e.target.checked) }),
      'TTS',
    ),
    h('button', { onClick: onClear, style: _VS.clearBtn }, 'Wyczysc'),
  );
}

// ── VoiceBubbles — transcript + response + error ────────────

function VoiceBubbles({ transcript, response, error }) {
  const h = React.createElement;
  return h(React.Fragment, null,
    transcript && h('div', { style: _bubbleStyle('user') }, h('span', { style: _roleLabelStyle('user') }, 'Ty: '), transcript),
    response && h('div', { style: _bubbleStyle('ai') }, h('span', { style: _roleLabelStyle('ai') }, 'proxym: '), response),
    error && h('div', { style: _VS.error }, error),
  );
}

// ── VoiceCommands — quick-action chip buttons ───────────────

const _VOICE_CMDS = ['uruchom vscode','zatrzymaj vscode','status vscode','pokaz VM-y','ile wydalem','logi','status','test routing','jakie modele','pokaz konta'];

function VoiceCommands({ onSend }) {
  const h = React.createElement;
  return h('details', { style: { marginTop: '8px' } },
    h('summary', { style: { fontSize: '11px', color: '#555', cursor: 'pointer' } }, 'Dostepne komendy'),
    h('div', { style: { display: 'flex', flexWrap: 'wrap', gap: '4px', marginTop: '6px' } },
      _VOICE_CMDS.map(cmd => h('button', { key: cmd, onClick: () => onSend(cmd), style: _VS.chipBtn }, cmd))
    ),
  );
}

// ── VoiceHistoryBox — scrollable history ────────────────────

function VoiceHistoryBox({ history }) {
  const h = React.createElement;
  if (!history.length) return null;
  return h('div', { style: _VS.historyBox },
    history.slice(-8).map((m, i) =>
      h('div', { key: `${m.role}-${i}`, style: { color: m.role === 'user' ? '#4338ca' : '#065f46', fontSize: '11px', padding: '1px 0' } },
        (m.role === 'user' ? 'Ty: ' : 'AI: ') + m.content
      )
    ),
  );
}

// ── _speakTTS — fire-and-forget TTS ─────────────────────────

function _speakTTS(text, lang, onEnd) {
  if (!window.speechSynthesis || !text) { onEnd(); return; }
  const u = new SpeechSynthesisUtterance(text);
  u.lang = lang;
  u.rate = 1.05;
  u.onend = onEnd;
  u.onerror = onEnd;
  window.speechSynthesis.speak(u);
}

// ── _createRecognizer — build SpeechRecognition instance ────

function _createRecognizer(lang, { onStart, onError, onResult }) {
  const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
  if (!SR) return null;
  const r = new SR();
  r.lang = lang;
  r.continuous = false;
  r.interimResults = true;
  r.onstart = onStart;
  r.onerror = onError;
  r.onresult = onResult;
  return r;
}

// ── VoiceChat — main component (thin shell) ─────────────────

function VoiceChat({ proxymBase, apiKey, model: initialModel = 'cheap' }) {
  setVoiceCredentials(proxymBase, apiKey);

  const h = React.createElement;
  const [state, setState] = React.useState('idle');
  const [transcript, setTranscript] = React.useState('');
  const [response, setResponse] = React.useState('');
  const [statusMsg, setStatusMsg] = React.useState('');
  const [history, setHistory] = React.useState([]);
  const [error, setError] = React.useState('');
  const [ttsEnabled, setTtsEnabled] = React.useState(true);
  const [model, setModel] = React.useState(initialModel);
  const [lang, setLang] = React.useState('pl-PL');

  const recRef = React.useRef(null);
  const abortRef = React.useRef(null);

  const hasSR = !!(window.SpeechRecognition || window.webkitSpeechRecognition);
  const hasTTS = !!window.speechSynthesis;

  function finish(text, userText) {
    setHistory(prev => [...prev.slice(-10), { role: 'user', content: userText }, { role: 'assistant', content: text }]);
    if (ttsEnabled && hasTTS) {
      setState('speaking');
      _speakTTS(text, lang, () => setState('idle'));
    } else {
      setState('idle');
    }
  }

  async function handleInput(text) {
    if (!text.trim()) return;
    setState('thinking');
    const ctrl = new AbortController();
    abortRef.current = ctrl;
    try {
      const reply = await processVoiceInput(text, {
        history, model, lang, signal: ctrl.signal,
        onStatus: setStatusMsg,
      });
      if (reply) {
        setResponse(reply);
        setStatusMsg('');
        finish(reply, text);
      }
    } catch (e) {
      if (e.name !== 'AbortError') {
        setError(`Blad: ${e.message}`);
        setState('idle');
      }
    }
  }

  function startListening() {
    if (state !== 'idle') return;
    setError(''); setTranscript(''); setResponse(''); setStatusMsg('');
    if (window.speechSynthesis?.speaking) window.speechSynthesis.cancel();
    if (!hasSR) { setError('Brak Web Speech API.'); return; }

    const r = _createRecognizer(lang, {
      onStart: () => setState('listening'),
      onError: (e) => { setError(`Mikrofon: ${e.error}`); setState('idle'); },
      onResult: (e) => {
        const text = Array.from(e.results).map(res => res[0].transcript).join('');
        setTranscript(text);
        if (e.results[e.results.length - 1].isFinal) { r.stop(); handleInput(text); }
      },
    });
    if (!r) return;
    r.onend = () => { if (state === 'listening') setState('idle'); };
    recRef.current = r;
    r.start();
  }

  function stopAll() {
    recRef.current?.abort();
    window.speechSynthesis?.cancel();
    abortRef.current?.abort();
    setState('idle');
  }

  React.useEffect(() => {
    const onKey = (e) => {
      if (e.code === 'Space' && e.target === document.body) {
        e.preventDefault();
        if (state === 'idle') startListening(); else stopAll();
      }
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [state]);

  const sc = _STATE_CONFIG[state] || _STATE_CONFIG.idle;
  const label = state === 'thinking' ? (statusMsg || sc.label) : sc.label;

  return h('div', { style: _VS.container },
    h(VoiceHeader, { model, lang, ttsEnabled, onModel: setModel, onLang: setLang, onTts: setTtsEnabled,
      onClear: () => { setHistory([]); setResponse(''); setTranscript(''); setError(''); }, hasSR, hasTTS }),
    h('button', { onClick: state === 'idle' ? startListening : stopAll,
      style: { ..._VS.micBtn, background: sc.color }, title: 'Spacja = nasluchuj' }, sc.icon),
    h('div', { style: { ..._VS.stateLabel, color: sc.color } }, label),
    h('div', { style: _VS.hint }, 'Spacja = nasluchuj / zatrzymaj'),
    h(VoiceBubbles, { transcript, response, error }),
    h(VoiceCommands, { onSend: handleInput }),
    h(VoiceHistoryBox, { history }),
  );
}
