// VoiceComposer — live speech-to-text via Web Speech API.
// listening: shows real-time transcript → stop sends text to AI
// typing: manual text input

const composerStyles = {
  fabWrap: {
    position: 'absolute', right: 16, bottom: 168,
    zIndex: 95,
  },
  fab: {
    width: 58, height: 58, borderRadius: 999,
    background: 'var(--firoozeh)', color: '#fff',
    display: 'grid', placeItems: 'center',
    border: 'none', cursor: 'pointer',
    boxShadow: '0 4px 12px rgba(42,157,143,0.30), 0 12px 28px rgba(42,157,143,0.18)',
    transition: 'transform 120ms ease-out, background 120ms ease-out',
  },
  fabListening: {
    background: 'var(--firoozeh-deep)',
    animation: 'sbPulseFab 2s ease-in-out infinite',
  },

  panel: {
    position: 'absolute', insetInlineStart: 14, insetInlineEnd: 14,
    bottom: 168, zIndex: 94, direction: 'rtl',
  },

  // Typing pill
  pill: {
    display: 'flex', alignItems: 'center', gap: 8,
    padding: 8,
    background: 'rgba(248,249,250,0.96)',
    backdropFilter: 'blur(20px) saturate(180%)',
    WebkitBackdropFilter: 'blur(20px) saturate(180%)',
    border: '1px solid rgba(25,28,29,0.08)',
    borderRadius: 999,
    boxShadow: '0 4px 16px rgba(0,0,0,0.08), 0 16px 32px rgba(0,0,0,0.06)',
  },

  // Listening card (expandable)
  listeningCard: {
    background: 'rgba(255,255,255,0.97)',
    backdropFilter: 'blur(20px) saturate(180%)',
    WebkitBackdropFilter: 'blur(20px) saturate(180%)',
    border: '1px solid rgba(25,28,29,0.08)',
    borderRadius: 24,
    boxShadow: '0 4px 20px rgba(42,157,143,0.10), 0 16px 32px rgba(0,0,0,0.08)',
    overflow: 'hidden',
    maxHeight: 'min(42vh, 320px)',
    display: 'flex',
    flexDirection: 'column',
  },
  listeningTop: {
    display: 'flex', alignItems: 'center', gap: 8,
    padding: 8,
  },
  liveBox: {
    padding: '2px 16px 14px',
    font: "400 16px/1.75 'Estedad', sans-serif",
    direction: 'rtl', textAlign: 'right',
    color: 'var(--ink)',
    minHeight: 36,
    flex: '1 1 auto',
    overflowY: 'auto',
    overscrollBehavior: 'contain',
  },
  liveHint: {
    padding: '2px 16px 14px',
    font: "400 14px 'Estedad', sans-serif",
    color: 'var(--ink-3)', textAlign: 'right', direction: 'rtl',
    flex: '1 1 auto',
  },

  fieldInput: {
    flex: 1, padding: '0 12px',
    background: 'transparent', border: 'none', outline: 'none',
    font: "400 15px/1.4 'Estedad', sans-serif",
    color: 'var(--ink)', minWidth: 0, textAlign: 'right',
  },
  iconBtn: {
    width: 38, height: 38, borderRadius: 999,
    background: 'transparent', color: 'var(--ink-2)',
    display: 'grid', placeItems: 'center',
    border: 'none', cursor: 'pointer', flex: 'none',
  },
  send: {
    width: 38, height: 38, borderRadius: 999,
    background: 'var(--ink-4)', color: 'var(--paper)',
    display: 'grid', placeItems: 'center',
    border: 'none', cursor: 'pointer', flex: 'none',
    transition: 'background 120ms',
  },
  sendActive: { background: 'var(--firoozeh)', color: '#fff' },
  stopBtn: {
    width: 38, height: 38, borderRadius: 999,
    background: 'var(--garnet)', color: '#fff',
    display: 'grid', placeItems: 'center',
    border: 'none', cursor: 'pointer', flex: 'none',
  },
  sendVoiceBtn: {
    width: 38, height: 38, borderRadius: 999,
    background: 'var(--firoozeh)', color: '#fff',
    display: 'grid', placeItems: 'center',
    border: 'none', cursor: 'pointer', flex: 'none',
  },
  timer: {
    font: "500 13px 'Estedad', sans-serif",
    color: 'var(--firoozeh-deep)',
    padding: '0 4px', flex: 'none', minWidth: 36, textAlign: 'left',
  },

  wave: { display: 'flex', alignItems: 'center', gap: 3, height: 26, flex: 1, justifyContent: 'center', padding: '0 4px' },
  bar1: { display: 'block', width: 3, background: 'var(--firoozeh)', borderRadius: 2 },

  globalCss: `
    @keyframes sbPulseFab {
      0%, 100% { box-shadow: 0 0 0 0 rgba(42,157,143,0.28), 0 4px 12px rgba(42,157,143,0.30); }
      50%      { box-shadow: 0 0 0 14px rgba(42,157,143,0.00), 0 4px 12px rgba(42,157,143,0.30); }
    }
    @keyframes sbWave {
      0%, 100% { transform: scaleY(0.3); }
      50%      { transform: scaleY(1); }
    }
  `,
};

function Wave({ bars = 14 }) {
  return (
    <div style={composerStyles.wave}>
      {Array.from({ length: bars }).map((_, i) => (
        <i key={i} style={{
          ...composerStyles.bar1,
          height: 5 + Math.abs(((i * 7) % 16) - 8),
          animation: `sbWave 0.9s ease-in-out ${(i % 5) * 0.1}s infinite`,
          transformOrigin: 'center',
        }} />
      ))}
    </div>
  );
}

const toFa = n => String(n).replace(/\d/g, d => '۰۱۲۳۴۵۶۷۸۹'[d]);

const _voiceClean = (value) => String(value || '')
  .replace(/[\u200c\s]+/g, ' ')
  .replace(/\s+([،؛:؟.!?])/g, '$1')
  .trim();

const _voiceWords = (value) => _voiceClean(value).split(' ').filter(Boolean);
const _voiceNormWord = (value) => String(value || '')
  .replace(/[،؛:؟.!?"'«»()[\]{}]/g, '')
  .toLocaleLowerCase('fa-IR');

function _voiceAppendableChunk(committed, incoming) {
  const baseWords = _voiceWords(committed);
  const nextWords = _voiceWords(incoming);
  if (!nextWords.length) return '';

  const baseNorm = baseWords.map(_voiceNormWord).filter(Boolean);
  const nextNorm = nextWords.map(_voiceNormWord).filter(Boolean);
  if (!nextNorm.length) return '';

  const baseKey = baseNorm.join(' ');
  const nextKey = nextNorm.join(' ');
  if (baseKey && (nextKey === baseKey || baseKey.endsWith(nextKey))) return '';

  if (
    baseNorm.length &&
    nextNorm.length >= baseNorm.length &&
    baseNorm.every((word, index) => nextNorm[index] === word)
  ) {
    return nextWords.slice(baseNorm.length).join(' ');
  }

  let overlap = 0;
  const maxOverlap = Math.min(16, baseNorm.length, nextNorm.length);
  for (let size = maxOverlap; size > 0; size--) {
    const baseTail = baseNorm.slice(baseNorm.length - size).join(' ');
    const nextHead = nextNorm.slice(0, size).join(' ');
    if (baseTail && baseTail === nextHead) {
      overlap = size;
      break;
    }
  }

  return nextWords.slice(overlap).join(' ');
}

window._voiceAppendableChunk = _voiceAppendableChunk;

function VoiceComposer({ mode, setMode, onSubmit, isDesktop }) {
  const { Icons } = window;
  const [text, setText]         = React.useState('');
  const [elapsed, setElapsed]   = React.useState(0);
  const [liveText, setLiveText] = React.useState('');
  const [interim, setInterim]   = React.useState('');
  const [noSR, setNoSR]         = React.useState(false);
  const [srDenied, setSrDenied] = React.useState(false);
  const [isRecording, setIsRecording] = React.useState(false);
  const [srMessage, setSrMessage] = React.useState('');

  const inputRef    = React.useRef(null);
  const recRef      = React.useRef(null);
  const finalRef    = React.useRef('');   // all committed utterances
  const currentRef  = React.useRef('');   // text from utterance in progress
  const activeRef   = React.useRef(false);
  const maxTimerRef = React.useRef(null);
  const srMessageRef = React.useRef('');
  const sessionRef = React.useRef(0);

  const commitFinalChunk = (rawChunk) => {
    const chunk = _voiceAppendableChunk(finalRef.current, rawChunk);
    if (!chunk) return finalRef.current;
    finalRef.current = _voiceClean(`${finalRef.current} ${chunk}`);
    return finalRef.current;
  };

  const updateSrMessage = (message) => {
    srMessageRef.current = message || '';
    setSrMessage(message || '');
  };

  // ── Timer ──────────────────────────────────────────────────────
  React.useEffect(() => {
    if (mode !== 'listening') { setElapsed(0); return; }
    const t = setInterval(() => setElapsed(e => e + 1), 1000);
    return () => clearInterval(t);
  }, [mode]);

  React.useEffect(() => {
    if (mode === 'typing') inputRef.current?.focus();
  }, [mode]);

  // ── Speech Recognition lifecycle ───────────────────────────────
  React.useEffect(() => {
    if (mode === 'listening') {
      startRecognition();
      maxTimerRef.current = setTimeout(() => {
        stopRecognition();
        updateSrMessage(finalRef.current
          ? 'ضبط به سقف زمان رسید. متن آماده‌ی ارسال است.'
          : 'مهلت ضبط تمام شد. دوباره تلاش کن.');
      }, 45000);
    } else {
      if (maxTimerRef.current) { clearTimeout(maxTimerRef.current); maxTimerRef.current = null; }
      stopRecognition();
      setLiveText('');
      setInterim('');
      updateSrMessage('');
      finalRef.current = '';
      currentRef.current = '';
    }
    return () => {
      if (maxTimerRef.current) { clearTimeout(maxTimerRef.current); maxTimerRef.current = null; }
      stopRecognition();
    };
  }, [mode]);

  const startRecognition = () => {
    const SR = window.SpeechRecognition || window.webkitSpeechRecognition;
    if (!SR) { setNoSR(true); return; }

    if (recRef.current) {
      try { recRef.current.abort ? recRef.current.abort() : recRef.current.stop(); } catch {}
      recRef.current = null;
    }

    activeRef.current = true;
    const sessionId = sessionRef.current + 1;
    sessionRef.current = sessionId;
    setNoSR(false);
    setSrDenied(false);
    updateSrMessage('');

    // Chrome on Android can end a Web Speech session immediately when
    // continuous mode is enabled, then emit start/end in a tight loop. Keep
    // each recording to one stable utterance and let the user retry if needed.
    const launchUtterance = () => {
      if (!activeRef.current || sessionId !== sessionRef.current) return;

      const rec = new SR();
      rec.lang = 'fa-IR';
      rec.continuous = false;
      rec.interimResults = true;
      rec.maxAlternatives = 1;
      recRef.current = rec;

      rec.onstart = () => {
        if (sessionId !== sessionRef.current) return;
        setIsRecording(true);
        updateSrMessage('');
      };

      rec.onresult = (e) => {
        if (sessionId !== sessionRef.current) return;
        let interimBuf = '';
        for (let i = e.resultIndex; i < e.results.length; i++) {
          const r = e.results[i];
          if (r.isFinal) commitFinalChunk(r[0].transcript);
          else interimBuf = _voiceClean(`${interimBuf} ${r[0].transcript}`);
        }
        setLiveText(finalRef.current);
        setInterim(_voiceAppendableChunk(finalRef.current, interimBuf));
      };

      rec.onerror = (e) => {
        if (sessionId !== sessionRef.current) return;
        setIsRecording(false);
        if (e.error === 'not-allowed' || e.error === 'service-not-allowed') {
        setNoSR(true);
        setSrDenied(true);
          updateSrMessage('دسترسی به میکروفون رد شد. از تنظیمات مرورگر مجوز بده.');
        } else if (e.error === 'no-speech') {
          updateSrMessage('چیزی شنیده نشد. نزدیک‌تر به میکروفون بگو و دوباره تلاش کن.');
        } else if (e.error === 'network') {
          updateSrMessage('تشخیص گفتار به اینترنت وصل نشد. اتصال را بررسی کن.');
        } else if (e.error !== 'aborted') {
          updateSrMessage('ضبط متوقف شد. دوباره تلاش کن.');
        }
      };

      rec.onend = () => {
        if (sessionId !== sessionRef.current) return;
        if (recRef.current === rec) recRef.current = null;
        activeRef.current = false;
        setIsRecording(false);
        setInterim('');
        if (!finalRef.current && !srMessageRef.current) {
          updateSrMessage('ضبط آماده‌ی تلاش دوباره است.');
        }
      };

      try {
        rec.start();
      } catch {
        if (sessionId === sessionRef.current) {
          activeRef.current = false;
          setIsRecording(false);
          updateSrMessage('ضبط شروع نشد. دوباره تلاش کن.');
        }
      }
    };

    launchUtterance();
  };

  const stopRecognition = () => {
    sessionRef.current += 1;
    activeRef.current = false;
    setIsRecording(false);
    if (recRef.current) {
      try { recRef.current.abort ? recRef.current.abort() : recRef.current.stop(); } catch {}
      recRef.current = null;
    }
  };

  // ── Handlers ───────────────────────────────────────────────────
  const handleSendVoice = () => {
    const transcript = _voiceClean(`${finalRef.current} ${_voiceAppendableChunk(finalRef.current, interim)}`);
    stopRecognition();
    if (transcript) onSubmit(transcript, 'voice', elapsed);
    setMode('collapsed');
  };

  const handleStopVoice = () => {
    stopRecognition();
    if (!finalRef.current) updateSrMessage('ضبط متوقف شد. برای شروع دوباره میکروفون را بزن.');
  };

  const handleRetryVoice = () => {
    setInterim('');
    updateSrMessage('');
    startRecognition();
  };

  const handleCancel = () => {
    stopRecognition();
    setMode('collapsed');
  };

  const handleSendText = () => {
    const t = text.trim();
    if (!t) return;
    onSubmit(t, 'text');
    setText('');
    setMode('collapsed');
  };

  const mm = Math.floor(elapsed / 60);
  const ss = elapsed % 60;
  const timer = `${toFa(mm)}:${toFa(String(ss).padStart(2, '0'))}`;
  const hasTranscript = (liveText + interim).trim().length > 0;

  // ── Collapsed: just FAB ────────────────────────────────────────
  if (mode === 'collapsed') {
    if (isDesktop) return null;
    const srSupported = !!(window.SpeechRecognition || window.webkitSpeechRecognition);
    return (
      <>
        <style>{composerStyles.globalCss}</style>
        <div style={composerStyles.fabWrap}>
          <button
            style={{ ...composerStyles.fab, ...(!srSupported ? { opacity: 0.45, cursor: 'not-allowed' } : {}) }}
            onClick={srSupported ? () => setMode('listening') : undefined}
            aria-label="ضبط صدا"
            disabled={!srSupported}
          >
            <Icons.Mic size={24} />
          </button>
        </div>
      </>
    );
  }

  const panelStyle = isDesktop
    ? { ...composerStyles.panel, bottom: 20 }
    : composerStyles.panel;

  // ── Listening card ─────────────────────────────────────────────
  if (mode === 'listening') {
    return (
      <>
        <style>{composerStyles.globalCss}</style>
        <div style={panelStyle}>
          <div style={composerStyles.listeningCard}>

            {/* Control row */}
            <div style={composerStyles.listeningTop}>
              {/* Cancel */}
              <button style={composerStyles.iconBtn} onClick={handleCancel} aria-label="لغو">
                <Icons.X size={18} />
              </button>

              {/* Live wave or status message */}
              {noSR ? (
                <span style={{ flex: 1, textAlign: 'center', font: "400 12px 'Estedad', sans-serif", color: 'var(--ink-3)', padding: '0 8px', lineHeight: 1.5 }}>
                  {!window.isSecureContext
                    ? 'میکروفون فقط روی HTTPS کار می‌کند'
                    : srDenied
                      ? 'دسترسی به میکروفون رد شد. در تنظیمات مرورگر مجوز بده.'
                      : 'مرورگر از میکروفون پشتیبانی نمی‌کند'}
                </span>
              ) : isRecording ? (
                <Wave />
              ) : (
                <span style={{ flex: 1, textAlign: 'center', font: "500 12px 'Estedad', sans-serif", color: 'var(--ink-3)', padding: '0 8px', lineHeight: 1.5 }}>
                  {srMessage || 'برای ادامه، دوباره ضبط را شروع کن'}
                </span>
              )}

              {/* Timer */}
              <span style={composerStyles.timer}>{timer}</span>

              {/* Send / Stop / Retry */}
              {hasTranscript ? (
                <button style={composerStyles.sendVoiceBtn} onClick={handleSendVoice} aria-label="ارسال">
                  <Icons.ArrowUp size={18} />
                </button>
              ) : isRecording ? (
                <button style={composerStyles.stopBtn} onClick={handleStopVoice} aria-label="پایان ضبط">
                  <span style={{ width: 12, height: 12, background: '#fff', borderRadius: 2, display: 'block' }} />
                </button>
              ) : (
                <button style={composerStyles.sendVoiceBtn} onClick={handleRetryVoice} aria-label="تلاش دوباره">
                  <Icons.Mic size={18} />
                </button>
              )}
            </div>

            {/* Live transcript */}
            {hasTranscript ? (
              <div style={composerStyles.liveBox}>
                {liveText}
                {interim && <span style={{ opacity: 0.45 }}>{interim}</span>}
              </div>
            ) : (
              <div style={composerStyles.liveHint}>
                {noSR ? '' : (srMessage || (isRecording ? 'بگو، داری شنیده می‌شوی…' : 'برای شروع دوباره، دکمه‌ی میکروفون را بزن.'))}
              </div>
            )}

          </div>
        </div>
      </>
    );
  }

  // ── Typing pill ────────────────────────────────────────────────
  return (
    <>
      <style>{composerStyles.globalCss}</style>
      <div style={panelStyle}>
        <div style={composerStyles.pill}>
          <button
            style={composerStyles.iconBtn}
            onClick={() => { setMode('collapsed'); setText(''); }}
            aria-label="بستن"
          >
            <Icons.X size={18} />
          </button>
          <input
            ref={inputRef}
            style={composerStyles.fieldInput}
            value={text}
            onChange={e => setText(e.target.value)}
            onKeyDown={e => e.key === 'Enter' && handleSendText()}
            placeholder="چی توی ذهنته؟"
          />
          <button style={composerStyles.iconBtn} onClick={() => setMode('listening')} aria-label="صدا">
            <Icons.Mic size={18} />
          </button>
          <button
            style={{ ...composerStyles.send, ...(text.trim() ? composerStyles.sendActive : {}) }}
            onClick={handleSendText}
            aria-label="بفرست"
          >
            <Icons.ArrowUp size={18} />
          </button>
        </div>
      </div>
    </>
  );
}

window.VoiceComposer = VoiceComposer;
