/* Practice — Praticar */
const { useState: useStateP, useEffect: useEffectP, useRef: useRefP } = React;

const PRON_PHRASES = [
  "I'd like to schedule a meeting for next Monday.",
  "Could you send me the report by end of day?",
  "I really appreciate your feedback on this.",
  "Let me think about it and get back to you.",
  "The presentation went really well this morning.",
  "I'm looking forward to working with your team.",
  "We need to discuss the budget before Friday.",
  "Thanks for joining the call on such short notice.",
];

const TOPIC_OPTIONS = [
  { v: 'work',       label: 'Trabalho' },
  { v: 'travel',     label: 'Viagem' },
  { v: 'small-talk', label: 'Small talk' },
  { v: 'daily-life', label: 'Vida diária' },
  { v: 'opinions',   label: 'Opiniões' },
];

const LEVEL_OPTIONS = ['A2', 'B1', 'B2', 'C1'];

// --- API helpers ---

async function apiPost(url, body) {
  const res = await fetch(url, {
    method: 'POST',
    credentials: 'same-origin',
    headers: { 'content-type': 'application/json' },
    body: JSON.stringify(body),
  });
  const d = await res.json();
  if (!res.ok) throw new Error(d.error || `Erro em ${url}.`);
  return d;
}

async function apiPostForm(url, form) {
  const res = await fetch(url, { method: 'POST', credentials: 'same-origin', body: form });
  const d = await res.json();
  if (!res.ok) throw new Error(d.error || `Erro em ${url}.`);
  return d;
}

function blobForm(blob, extra) {
  const form = new FormData();
  const ext = blob.type.includes('mp4') ? 'mp4' : 'webm';
  form.append('audio', blob, `audio.${ext}`);
  Object.entries(extra).forEach(([k, v]) => { if (v != null) form.append(k, String(v)); });
  return form;
}

const apiStartConversation = (mode, topic, level) =>
  apiPost('/api/start-conversation', { mode: mode === 'free' ? 'real' : mode, topic, level });

const apiEvaluateAudio = (blob, { coachPrompt, topic, level, sessionId }) =>
  apiPostForm('/api/evaluate-audio', blobForm(blob, { coachPrompt, topic, level, sessionId }));

const apiConversationTurn = (blob, { sessionId, topic, level }) =>
  apiPostForm('/api/conversation-turn', blobForm(blob, { sessionId, topic, level }));

const apiConversationSummary = (sessionId, topic, level) =>
  apiPost('/api/conversation-summary', { sessionId, topic, level });

const apiPronunciationDrill = (blob, { targetPhrase, level }) =>
  apiPostForm('/api/pronunciation-drill', blobForm(blob, { targetPhrase, level }));

// --- TTS (Web Speech API, browser-only, no backend) ---

const tts = {
  supported: typeof window !== 'undefined' && 'speechSynthesis' in window,
  voice: null,
  pickVoice() {
    if (!this.supported) return null;
    const voices = window.speechSynthesis.getVoices();
    if (!voices.length) return null;
    const en = voices.filter((v) => /^en[-_]/i.test(v.lang));
    this.voice =
      en.find((v) => /google.*(us|english)/i.test(v.name)) ||
      en.find((v) => /natural|aria|jenny|samantha|libby/i.test(v.name)) ||
      en.find((v) => /^en[-_]us/i.test(v.lang)) ||
      en[0] || null;
    return this.voice;
  },
  speak(text) {
    if (!this.supported || !text) return;
    window.speechSynthesis.cancel();
    const u = new SpeechSynthesisUtterance(text);
    u.lang = 'en-US';
    const v = this.voice || this.pickVoice();
    if (v) u.voice = v;
    u.rate = 0.95;
    u.pitch = 1;
    window.speechSynthesis.speak(u);
  },
  cancel() {
    if (this.supported) window.speechSynthesis.cancel();
  },
};
if (tts.supported) {
  tts.pickVoice();
  window.speechSynthesis.onvoiceschanged = () => tts.pickVoice();
}

// --- Sub-components ---

function ScoreBar({ label, value }) {
  const pct = Math.min(100, Math.max(0, value || 0));
  const color = pct >= 80 ? 'var(--green)' : pct >= 60 ? 'var(--amber)' : 'var(--coral)';
  return (
    <div className="fb-score">
      <span>{label}</span>
      <strong style={{ color }}>{(pct / 10).toFixed(1)}</strong>
    </div>
  );
}

function FeedbackCard({ data }) {
  const fix = Array.isArray(data.fix) ? data.fix : [];
  return (
    <div className="feedback-msg">
      <div className="fb-head"><Icon name="sparkle" size={15} /> Avaliação da sua resposta</div>
      <div className="fb-scores">
        <ScoreBar label="Pronúncia" value={data.pronunciation} />
        <ScoreBar label="Fluência"  value={data.fluency} />
        <ScoreBar label="Gramática" value={data.grammar} />
        <ScoreBar label="Vocab."    value={data.vocabulary} />
      </div>
      {fix.length > 0 && (
        <p className="fb-correct">
          <b>Correção: </b>
          {fix.map((p, i) =>
            typeof p === 'string'
              ? <span key={i}>{p}</span>
              : <b key={i} style={{ color: p.t === 'error' ? 'var(--coral)' : 'var(--green)' }}>{p.w}</b>
          )}
          {data.better && <><br /><b>Mais natural: </b><span className="better">{data.better}</span></>}
        </p>
      )}
    </div>
  );
}

function PronCard({ data, phrase }) {
  const score = data.score ?? 0;
  const color = score >= 80 ? 'var(--green)' : score >= 60 ? 'var(--amber)' : 'var(--coral)';
  return (
    <div className="feedback-msg">
      <div className="fb-head"><Icon name="waves" size={15} /> Resultado de pronúncia</div>
      <p style={{ fontSize: '14px', color: 'var(--ink-faint)', margin: '0 0 6px' }}>
        Frase: <em style={{ color: 'var(--ink)' }}>"{phrase}"</em>
      </p>
      <p style={{ fontSize: '14px', color: 'var(--ink-faint)', margin: '0 0 12px' }}>
        Você disse: <em style={{ color: 'var(--ink)' }}>"{data.transcript}"</em>
      </p>
      <div className="fb-scores">
        <div className="fb-score">
          <span>Score</span>
          <strong style={{ color, fontSize: '20px' }}>{Number(score).toFixed(0)}</strong>
        </div>
      </div>
      {data.feedback && <p className="fb-correct" style={{ marginTop: '10px' }}>{data.feedback}</p>}
    </div>
  );
}

function Message({ m }) {
  if (m.type === 'feedback') return <FeedbackCard data={m.data} />;
  if (m.type === 'pron')     return <PronCard data={m.data} phrase={m.phrase} />;
  const isUser = m.type === 'user';
  return (
    <div className={'msg ' + (isUser ? 'user' : 'coach')}>
      <div className="msg-avatar">{isUser ? 'V' : 'A'}</div>
      <div className="msg-bubble">
        {m.text}
        {!isUser && tts.supported && (
          <button
            className="tts-replay"
            onClick={() => tts.speak(m.speak || m.text)}
            aria-label="Ouvir novamente"
            title="Ouvir novamente"
          >
            <Icon name="volume" size={14} />
          </button>
        )}
      </div>
    </div>
  );
}

function Recorder({ recording, onToggle, canSend, onSend, seconds, disabled }) {
  const [bars, setBars] = useStateP(() => Array.from({ length: 28 }, () => 14));
  useEffectP(() => {
    if (!recording) { setBars(Array.from({ length: 28 }, () => 14)); return; }
    const id = setInterval(() => setBars(Array.from({ length: 28 }, () => 10 + Math.random() * 28)), 110);
    return () => clearInterval(id);
  }, [recording]);
  const mm = String(Math.floor(seconds / 60)).padStart(1, '0');
  const ss = String(seconds % 60).padStart(2, '0');
  return (
    <div className={'recorder' + (recording ? ' is-recording' : '')}>
      <button className={'rec-btn' + (recording ? ' recording' : '')} onClick={onToggle} disabled={disabled}>
        <Icon name={recording ? 'check' : 'mic'} size={recording ? 24 : 22} stroke={2} />
      </button>
      <div className="rec-wave">
        {bars.map((h, i) => <i key={i} style={{ height: h + 'px' }} />)}
      </div>
      {recording
        ? <span className="rec-timer">{mm}:{ss}</span>
        : <span className="rec-hint">{canSend ? 'Pronto para enviar' : 'Toque para gravar'}</span>
      }
      <button className="send-btn" onClick={onSend} disabled={!canSend || disabled} aria-label="Enviar">
        <Icon name="send" size={20} />
      </button>
    </div>
  );
}

// --- Main component ---

function Practice() {
  const [mode,      setMode]      = useStateP('guided');
  const [topic,     setTopic]     = useStateP('work');
  const [level,     setLevel]     = useStateP('B1');
  const [phase,     setPhase]     = useStateP('setup'); // setup | loading | active | ending | done
  const [msgs,      setMsgs]      = useStateP([]);
  const [sessionId, setSessionId] = useStateP(null);
  const [coachPrompt, setCoachPrompt] = useStateP('');
  const [phraseIdx, setPhraseIdx] = useStateP(0);
  const [recording, setRecording] = useStateP(false);
  const [audioBlob, setAudioBlob] = useStateP(null);
  const [seconds,   setSeconds]   = useStateP(0);
  const [sending,   setSending]   = useStateP(false);
  const [typing,    setTyping]    = useStateP(false);
  const [error,     setError]     = useStateP('');
  const [summary,   setSummary]   = useStateP(null);
  const [muted,     setMuted]     = useStateP(false);

  const logRef    = useRefP(null);
  const mrRef     = useRefP(null);
  const chunksRef = useRefP([]);
  const timerRef  = useRefP(null);
  const spokenRef = useRefP(-1);

  useEffectP(() => {
    if (logRef.current) logRef.current.scrollTop = logRef.current.scrollHeight;
  }, [msgs, typing]);

  // Auto-play the coach's voice when a new coach message arrives.
  useEffectP(() => {
    const last = msgs.length - 1;
    if (last < 0 || last <= spokenRef.current) return;
    const m = msgs[last];
    if (m.type !== 'coach') return;
    spokenRef.current = last;
    if (!muted) tts.speak(m.speak || m.text);
  }, [msgs]);

  // Stop any speech when leaving the screen.
  useEffectP(() => () => tts.cancel(), []);

  useEffectP(() => {
    if (recording) {
      setSeconds(0);
      timerRef.current = setInterval(() => setSeconds((s) => s + 1), 1000);
    } else {
      clearInterval(timerRef.current);
    }
    return () => clearInterval(timerRef.current);
  }, [recording]);

  const pushMsg = (m) => setMsgs((prev) => [...prev, m]);

  const handleStart = async () => {
    setError('');
    setPhase('loading');
    try {
      if (mode === 'pron') {
        const phrase = PRON_PHRASES[phraseIdx % PRON_PHRASES.length];
        setMsgs([{ type: 'coach', text: 'Vamos treinar sua pronúncia! Leia a frase abaixo e grave sua voz.', speak: phrase }]);
        setPhase('active');
        return;
      }
      const data = await apiStartConversation(mode, topic, level);
      setSessionId(data.sessionId || null);
      setCoachPrompt(data.message);
      setMsgs([{ type: 'coach', text: data.message }]);
      setPhase('active');
    } catch (e) {
      setError(e.message);
      setPhase('setup');
    }
  };

  const toggleRecording = async () => {
    if (recording) {
      mrRef.current?.stop();
      setRecording(false);
    } else {
      tts.cancel();
      setAudioBlob(null);
      setError('');
      try {
        const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
        const mimeType =
          MediaRecorder.isTypeSupported('audio/webm;codecs=opus') ? 'audio/webm;codecs=opus' :
          MediaRecorder.isTypeSupported('audio/webm')             ? 'audio/webm' :
                                                                    'audio/mp4';
        const mr = new MediaRecorder(stream, { mimeType });
        chunksRef.current = [];
        mr.ondataavailable = (e) => { if (e.data.size > 0) chunksRef.current.push(e.data); };
        mr.onstop = () => {
          const blob = new Blob(chunksRef.current, { type: mimeType });
          setAudioBlob(blob);
          stream.getTracks().forEach((t) => t.stop());
        };
        mr.start();
        mrRef.current = mr;
        setRecording(true);
      } catch {
        setError('Não foi possível acessar o microfone. Verifique as permissões do navegador.');
      }
    }
  };

  const handleSend = async () => {
    if (!audioBlob || sending) return;
    setError('');
    setSending(true);
    const blob = audioBlob;
    setAudioBlob(null);
    try {
      if (mode === 'guided') {
        setTyping(true);
        const data = await apiEvaluateAudio(blob, { coachPrompt, topic, level, sessionId });
        setTyping(false);
        pushMsg({ type: 'user', text: data.transcript });
        pushMsg({ type: 'feedback', data });
        if (data.nextCoachMessage) {
          pushMsg({ type: 'coach', text: data.nextCoachMessage });
          setCoachPrompt(data.nextCoachMessage);
        }
      } else if (mode === 'free') {
        setTyping(true);
        const data = await apiConversationTurn(blob, { sessionId, topic, level });
        setTyping(false);
        pushMsg({ type: 'user', text: data.transcript });
        pushMsg({ type: 'coach', text: data.coachMessage });
        setCoachPrompt(data.coachMessage);
      } else if (mode === 'pron') {
        const phrase = PRON_PHRASES[phraseIdx % PRON_PHRASES.length];
        setTyping(true);
        const data = await apiPronunciationDrill(blob, { targetPhrase: phrase, level });
        setTyping(false);
        pushMsg({ type: 'user', text: data.transcript });
        pushMsg({ type: 'pron', data, phrase });
        const next = (phraseIdx + 1) % PRON_PHRASES.length;
        setPhraseIdx(next);
        pushMsg({ type: 'coach', text: `Próxima frase: "${PRON_PHRASES[next]}"`, speak: PRON_PHRASES[next] });
      }
    } catch (e) {
      setTyping(false);
      setError(e.message);
    } finally {
      setSending(false);
    }
  };

  const handleEnd = async () => {
    tts.cancel();
    if (mode === 'free' && sessionId) {
      setPhase('ending');
      try {
        const s = await apiConversationSummary(sessionId, topic, level);
        setSummary(s);
      } catch {
        // show done screen anyway
      }
    }
    setPhase('done');
  };

  const reset = () => {
    tts.cancel();
    spokenRef.current = -1;
    setPhase('setup');
    setMsgs([]);
    setSessionId(null);
    setCoachPrompt('');
    setAudioBlob(null);
    setSending(false);
    setTyping(false);
    setError('');
    setSummary(null);
    setPhraseIdx(0);
  };

  const toggleMute = () => {
    setMuted((v) => {
      const next = !v;
      if (next) tts.cancel();
      return next;
    });
  };

  const MODES = [
    { k: 'guided', label: 'Treino guiado',  icon: 'mic' },
    { k: 'free',   label: 'Conversa livre', icon: 'message' },
    { k: 'pron',   label: 'Pronúncia',      icon: 'waves' },
  ];

  const isActive     = phase === 'active';
  const currentPhrase = PRON_PHRASES[phraseIdx % PRON_PHRASES.length];
  const topicLabel   = TOPIC_OPTIONS.find((t) => t.v === topic)?.label || topic;

  // --- Done screen ---
  if (phase === 'done') {
    return (
      <div className="practice-page" style={{ alignItems: 'center', justifyContent: 'center' }}>
        <div className="card" style={{ maxWidth: '480px', textAlign: 'center', padding: '40px 32px' }}>
          <div className="coach-portrait" style={{ margin: '0 auto 20px', background: 'var(--green-soft)', color: 'var(--green)' }}>
            <Icon name="check" size={32} stroke={2.4} />
          </div>
          <h2>Sessão encerrada!</h2>
          {summary?.highlights && (
            <p style={{ color: 'var(--ink-faint)', fontSize: '14px', margin: '12px 0 0' }}>{summary.highlights}</p>
          )}
          <button className="btn btn-primary btn-lg btn-block" style={{ marginTop: '28px' }} onClick={reset}>
            Nova sessão
          </button>
        </div>
      </div>
    );
  }

  // --- Main layout ---
  return (
    <div className="practice-page">
      <section className="chat-col">
        <div className="chat-top">
          <div className="mode-pills">
            {MODES.map((mo) => (
              <button
                key={mo.k}
                className={'mode-pill' + (mode === mo.k ? ' active' : '')}
                onClick={() => { if (!isActive) setMode(mo.k); }}
                disabled={isActive && mode !== mo.k}
              >
                <Icon name={mo.icon} size={16} /> {mo.label}
              </button>
            ))}
          </div>
          <div className="chat-ctx">
            <span className="ctx-select">Tema
              <select value={topic} onChange={(e) => setTopic(e.target.value)} disabled={isActive}>
                {TOPIC_OPTIONS.map((t) => <option key={t.v} value={t.v}>{t.label}</option>)}
              </select>
            </span>
            <span className="ctx-select">Nível
              <select value={level} onChange={(e) => setLevel(e.target.value)} disabled={isActive}>
                {LEVEL_OPTIONS.map((l) => <option key={l}>{l}</option>)}
              </select>
            </span>
          </div>
        </div>

        <div className="chat-log" ref={logRef}>
          {phase === 'setup' && (
            <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', height: '100%', gap: '16px' }}>
              {error && <p style={{ color: 'var(--coral)', fontSize: '14px' }}>{error}</p>}
              <p style={{ color: 'var(--ink-faint)', fontSize: '14px', textAlign: 'center' }}>
                Escolha o modo, tema e nível acima e clique em Começar.
              </p>
              <button className="btn btn-primary btn-lg" onClick={handleStart}>
                Começar sessão <Icon name="arrowRight" size={17} />
              </button>
            </div>
          )}
          {phase === 'loading' && (
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100%' }}>
              <p style={{ color: 'var(--ink-faint)', fontSize: '14px' }}>Preparando sua sessão...</p>
            </div>
          )}
          {msgs.map((m, i) => <Message key={i} m={m} />)}
          {typing && (
            <div className="msg coach">
              <div className="msg-avatar">A</div>
              <div className="msg-bubble" style={{ padding: 0 }}>
                <div className="chat-typing"><i /><i /><i /></div>
              </div>
            </div>
          )}
        </div>

        {isActive && (
          <div className="composer">
            {mode === 'pron' && (
              <div style={{ display: 'flex', alignItems: 'center', gap: '10px', padding: '8px 16px', background: 'var(--surface-2)', borderRadius: '8px', fontSize: '14px', color: 'var(--ink)', fontStyle: 'italic', marginBottom: '8px' }}>
                <span style={{ flex: 1 }}>"{currentPhrase}"</span>
                {tts.supported && (
                  <button
                    className="tts-replay"
                    onClick={() => tts.speak(currentPhrase)}
                    aria-label="Ouvir a frase"
                    title="Ouvir a frase"
                  >
                    <Icon name="volume" size={16} />
                  </button>
                )}
              </div>
            )}
            {error && <p style={{ color: 'var(--coral)', fontSize: '13px', margin: '0 0 6px' }}>{error}</p>}
            <Recorder
              recording={recording}
              onToggle={toggleRecording}
              canSend={!!audioBlob && !sending}
              onSend={handleSend}
              seconds={seconds}
              disabled={sending}
            />
          </div>
        )}
      </section>

      <aside className="coach-col">
        <div className="card coach-card">
          <div className="coach-portrait">A<span className="status-dot" /></div>
          <h3>Professor Alex</h3>
          <p className="role">Seu coach de conversação</p>
          <div className="coach-status-line">
            <Icon name={sending ? 'sparkle' : 'volume'} size={15} />
            {recording ? 'Gravando...' : sending ? 'Avaliando...' : isActive ? 'Ouvindo você' : 'Pronto'}
          </div>
          {tts.supported && (
            <button className="btn btn-ghost btn-block" style={{ marginTop: '12px' }} onClick={toggleMute}>
              <Icon name={muted ? 'volumeOff' : 'volume'} size={16} />
              {muted ? 'Ativar voz do coach' : 'Silenciar voz do coach'}
            </button>
          )}
        </div>

        <div className="card panel-block">
          <h4>Sessão atual</h4>
          <div className="ctx-line"><span>Modo</span><strong>{MODES.find((m) => m.k === mode)?.label}</strong></div>
          <div className="ctx-line"><span>Tema</span><strong>{topicLabel}</strong></div>
          <div className="ctx-line"><span>Nível</span><strong>{level}</strong></div>
        </div>

        {isActive && (
          <>
            <div className="card panel-block">
              <h4>Dicas do treino</h4>
              <div className="tip-list">
                <div className="tip-item"><Icon name="bulb" size={17} /> Responda com 2 ou 3 frases completas.</div>
                <div className="tip-item"><Icon name="bulb" size={17} /> Após a correção, repita a versão melhorada em voz alta.</div>
              </div>
            </div>
            <button className="btn btn-ghost btn-block" onClick={handleEnd} disabled={phase === 'ending'}>
              <Icon name="check" size={18} /> {phase === 'ending' ? 'Encerrando...' : 'Encerrar e ver resumo'}
            </button>
          </>
        )}
      </aside>
    </div>
  );
}

Object.assign(window, { Practice });
