/* ============================================================
   Exercises — Learn, Multiple-choice, Listening, Matching,
   Speaking, and the Flashcard/SRS review deck.
   Each renders its own footer (Check / Continue) and calls
   onNext(correct) to advance the runner.
   ============================================================ */
(function () {
  const { useState, useEffect, useRef } = React;
  const OK = 'oklch(0.60 0.13 150)';
  const NO = 'oklch(0.58 0.17 25)';
  const speak = window.speakRU;

  function shuffle(a){ const x=a.slice(); for(let i=x.length-1;i>0;i--){ const j=Math.floor(Math.random()*(i+1)); [x[i],x[j]]=[x[j],x[i]]; } return x; }

  /* ---- feedback sheet ------------------------------------------- */
  function Feedback({ status, title, sub, onNext }) {
    const ok = status === 'correct';
    return (
      <div style={{
        position:'absolute', left:0, right:0, bottom:0, zIndex:30,
        background: ok ? 'oklch(0.96 0.05 150)' : 'oklch(0.96 0.05 25)',
        borderTop:`1px solid ${ok?OK:NO}`,
        padding:'18px 18px calc(18px + env(safe-area-inset-bottom))',
        borderTopLeftRadius:24, borderTopRightRadius:24,
        animation:'sheetUp .28s cubic-bezier(.2,.9,.3,1)',
      }}>
        <div style={{ display:'flex', alignItems:'center', gap:12, marginBottom:14 }}>
          <div style={{ width:38, height:38, borderRadius:999, background: ok?OK:NO,
                        display:'flex', alignItems:'center', justifyContent:'center', flexShrink:0 }}>
            <svg width="22" height="22" viewBox="0 0 24 24">
              {ok ? <path d="M5 13l4 4 10-11" stroke="#fff" strokeWidth="2.6" fill="none" strokeLinecap="round" strokeLinejoin="round"/>
                  : <path d="M7 7l10 10M17 7L7 17" stroke="#fff" strokeWidth="2.6" fill="none" strokeLinecap="round"/>}
            </svg>
          </div>
          <div>
            <div style={{ fontFamily:'"Bricolage Grotesque", system-ui', fontWeight:800, fontSize:18,
                          color: ok?'oklch(0.42 0.12 150)':'oklch(0.42 0.15 25)' }}>{title}</div>
            {sub && <div style={{ fontFamily:'"Hanken Grotesk", system-ui', fontSize:13.5, fontWeight:600,
                          color: ok?'oklch(0.48 0.1 150)':'oklch(0.48 0.12 25)' }}>{sub}</div>}
          </div>
        </div>
        <Btn variant={ok?'primary':'dark'} full onClick={onNext}
          style={ok?{background:OK, boxShadow:`0 8px 20px -10px ${OK}`}:{background:NO}}>Continue</Btn>
      </div>
    );
  }

  function Prompt({ children }) {
    return <div style={{ fontFamily:'"Bricolage Grotesque", system-ui', fontWeight:800,
      fontSize:23, lineHeight:1.18, color:'var(--ink)', letterSpacing:'-0.02em',
      padding:'4px 4px 16px', textWrap:'pretty' }}>{children}</div>;
  }

  /* ---- 1 · Learn card ------------------------------------------- */
  function LearnCard({ item, onNext }) {
    return (
      <div style={{ display:'flex', flexDirection:'column', height:'100%' }}>
        <div style={{ flex:1, overflowY:'auto', padding:'4px 18px 20px' }}>
          <div style={{ fontFamily:'"JetBrains Mono",monospace', fontSize:11, fontWeight:600,
            letterSpacing:'0.14em', textTransform:'uppercase', color:'var(--primary-deep)',
            padding:'2px 2px 14px' }}>New {item.type}</div>
          <StackedGloss item={item} autoplay />
          <p style={{ fontFamily:'"Hanken Grotesk",system-ui', fontSize:14.5, fontWeight:500,
            color:'var(--muted)', lineHeight:1.5, padding:'18px 6px 0', textWrap:'pretty' }}>
            Tap any word to hear it on its own, or press <strong style={{color:'var(--ink)'}}>Listen</strong> to
            hear the whole {item.type} read at learner speed.
          </p>
        </div>
        <div style={{ padding:'10px 18px calc(16px + env(safe-area-inset-bottom))', borderTop:'1px solid var(--line)' }}>
          <Btn full onClick={onNext}>Got it</Btn>
        </div>
      </div>
    );
  }

  /* ---- 2 · Multiple choice -------------------------------------- */
  function ChoiceExercise({ ex, onNext }) {
    const [sel, setSel] = useState(null);
    const [done, setDone] = useState(false);
    const correct = sel === ex.answer;
    return (
      <div style={{ display:'flex', flexDirection:'column', height:'100%' }}>
        <div style={{ flex:1, overflowY:'auto', padding:'4px 18px 20px' }}>
          <Prompt>{ex.prompt}</Prompt>
          {ex.item && <div style={{ marginBottom:18 }}><StackedGloss item={ex.item} compact /></div>}
          <div style={{ display:'flex', flexDirection:'column', gap:11 }}>
            {ex.options.map(o => {
              const isSel = sel === o;
              const state = done ? (o === ex.answer ? 'ok' : (isSel ? 'no' : 'idle')) : (isSel ? 'sel' : 'idle');
              const styles = {
                idle:{ background:'var(--surface)', border:'1.5px solid var(--line)', color:'var(--ink)' },
                sel:{ background:'var(--primary-wash)', border:'1.5px solid var(--primary)', color:'var(--primary-deep)' },
                ok:{ background:'oklch(0.96 0.05 150)', border:`1.5px solid ${OK}`, color:'oklch(0.4 0.12 150)' },
                no:{ background:'oklch(0.96 0.05 25)', border:`1.5px solid ${NO}`, color:'oklch(0.42 0.14 25)' },
              }[state];
              const isRu = /[А-Яа-яЁё]/.test(o);
              return (
                <button key={o} disabled={done} onClick={() => setSel(o)}
                  style={{ appearance:'none', cursor: done?'default':'pointer', textAlign:'left',
                    padding:'15px 17px', borderRadius:15, ...styles,
                    fontFamily: isRu ? '"Golos Text", system-ui':'"Hanken Grotesk", system-ui',
                    fontWeight: isRu?600:700, fontSize: isRu?20:16.5, transition:'all .15s' }}>
                  {o}
                </button>
              );
            })}
          </div>
        </div>
        {!done
          ? <div style={{ padding:'10px 18px calc(16px + env(safe-area-inset-bottom))', borderTop:'1px solid var(--line)' }}>
              <Btn full disabled={sel==null} onClick={() => setDone(true)}>Check</Btn>
            </div>
          : <Feedback status={correct?'correct':'wrong'}
              title={correct?'Correct!':'Not quite'}
              sub={correct?null:`Answer: ${ex.answer}`}
              onNext={() => onNext(correct)} />}
      </div>
    );
  }

  /* ---- 3 · Listening -------------------------------------------- */
  function ListenExercise({ ex, onNext }) {
    const [sel, setSel] = useState(null);
    const [done, setDone] = useState(false);
    const [playing, setPlaying] = useState(false);
    const play = () => { setPlaying(true); speak(ex.item.ru, { onend:()=>setPlaying(false) }); };
    useEffect(() => { const id=setTimeout(play, 400); return ()=>clearTimeout(id); }, []); // eslint-disable-line
    const correct = sel === ex.answer;
    return (
      <div style={{ display:'flex', flexDirection:'column', height:'100%' }}>
        <div style={{ flex:1, overflowY:'auto', padding:'4px 18px 20px' }}>
          <Prompt>{ex.prompt}</Prompt>
          <div style={{ display:'flex', justifyContent:'center', padding:'8px 0 26px' }}>
            <button onClick={play} aria-label="Replay"
              style={{ appearance:'none', border:'none', cursor:'pointer', width:108, height:108,
                borderRadius:999, background:'var(--primary)', color:'#fff',
                display:'flex', alignItems:'center', justifyContent:'center',
                boxShadow:'0 16px 36px -14px var(--primary)',
                transform: playing?'scale(1.04)':'scale(1)', transition:'transform .2s' }}>
              <Speaker size={44} color="#fff" playing={playing} />
              {playing && <span style={{ position:'absolute', inset:-6, borderRadius:999,
                border:'3px solid var(--primary)', opacity:0.35, animation:'ping 1.1s ease-out infinite' }}/>}
            </button>
          </div>
          <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:11 }}>
            {ex.options.map(o => {
              const isSel = sel === o.ru;
              const state = done ? (o.ru===ex.answer?'ok':(isSel?'no':'idle')) : (isSel?'sel':'idle');
              const styles = {
                idle:{ background:'var(--surface)', border:'1.5px solid var(--line)' },
                sel:{ background:'var(--primary-wash)', border:'1.5px solid var(--primary)' },
                ok:{ background:'oklch(0.96 0.05 150)', border:`1.5px solid ${OK}` },
                no:{ background:'oklch(0.96 0.05 25)', border:`1.5px solid ${NO}` },
              }[state];
              return (
                <button key={o.ru} disabled={done} onClick={() => setSel(o.ru)}
                  style={{ appearance:'none', cursor:done?'default':'pointer', padding:'16px 12px',
                    borderRadius:15, ...styles, display:'flex', flexDirection:'column', gap:3,
                    alignItems:'center', transition:'all .15s' }}>
                  <span style={{ fontFamily:'"Golos Text",system-ui', fontWeight:600, fontSize:21, color:'var(--ink)' }}>{o.ru}</span>
                  {done && <span style={{ fontFamily:'"Hanken Grotesk",system-ui', fontSize:12.5, fontWeight:600, color:'var(--muted)' }}>{o.en}</span>}
                </button>
              );
            })}
          </div>
        </div>
        {!done
          ? <div style={{ padding:'10px 18px calc(16px + env(safe-area-inset-bottom))', borderTop:'1px solid var(--line)' }}>
              <Btn full disabled={sel==null} onClick={() => setDone(true)}>Check</Btn>
            </div>
          : <Feedback status={correct?'correct':'wrong'} title={correct?'Correct!':'Not quite'}
              sub={correct?ex.item.translation:`You heard “${ex.answer}”`} onNext={() => onNext(correct)} />}
      </div>
    );
  }

  /* ---- 4 · Matching pairs --------------------------------------- */
  function MatchExercise({ ex, onNext }) {
    const [left] = useState(() => shuffle(ex.pairs.map(p => p.ru)));
    const [right] = useState(() => shuffle(ex.pairs.map(p => p.en)));
    const [selRu, setSelRu] = useState(null);
    const [selEn, setSelEn] = useState(null);
    const [matched, setMatched] = useState({});
    const [wrong, setWrong] = useState(false);
    const allDone = Object.keys(matched).length === ex.pairs.length * 2;

    useEffect(() => {
      if (selRu && selEn) {
        const ok = ex.pairs.some(p => p.ru === selRu && p.en === selEn);
        if (ok) {
          speak(selRu);
          setMatched(m => ({ ...m, [selRu]:true, ['en:'+selEn]:true }));
          setSelRu(null); setSelEn(null);
        } else {
          setWrong(true);
          const id = setTimeout(() => { setWrong(false); setSelRu(null); setSelEn(null); }, 480);
          return () => clearTimeout(id);
        }
      }
    }, [selRu, selEn]); // eslint-disable-line

    const cell = (label, isRu, sel, onClick, isMatched) => {
      const wrongFlash = wrong && sel;
      return (
        <button key={label} disabled={isMatched} onClick={onClick}
          style={{ appearance:'none', cursor:isMatched?'default':'pointer', padding:'15px 10px',
            borderRadius:14, minHeight:54, transition:'all .15s',
            opacity:isMatched?0.28:1,
            background: wrongFlash?'oklch(0.96 0.05 25)':(sel?'var(--primary-wash)':'var(--surface)'),
            border:`1.5px solid ${wrongFlash?NO:(sel?'var(--primary)':'var(--line)')}`,
            fontFamily:isRu?'"Golos Text",system-ui':'"Hanken Grotesk",system-ui',
            fontWeight:isRu?600:700, fontSize:isRu?20:15.5,
            color: sel?'var(--primary-deep)':'var(--ink)' }}>
          {label}
        </button>
      );
    };
    return (
      <div style={{ display:'flex', flexDirection:'column', height:'100%' }}>
        <div style={{ flex:1, overflowY:'auto', padding:'4px 18px 20px' }}>
          <Prompt>{ex.prompt}</Prompt>
          <p style={{ fontFamily:'"Hanken Grotesk",system-ui', fontSize:13.5, fontWeight:600,
            color:'var(--muted)', padding:'0 2px 18px' }}>Tap a Russian word, then its English meaning.</p>
          <div style={{ display:'grid', gridTemplateColumns:'1fr 1fr', gap:11 }}>
            <div style={{ display:'flex', flexDirection:'column', gap:11 }}>
              {left.map(ru => cell(ru, true, selRu===ru, () => !matched[ru] && setSelRu(ru), !!matched[ru]))}
            </div>
            <div style={{ display:'flex', flexDirection:'column', gap:11 }}>
              {right.map(en => cell(en, false, selEn===en, () => !matched['en:'+en] && setSelEn(en), !!matched['en:'+en]))}
            </div>
          </div>
        </div>
        {!allDone
          ? <div style={{ padding:'10px 18px calc(16px + env(safe-area-inset-bottom))', borderTop:'1px solid var(--line)',
              textAlign:'center', fontFamily:'"Hanken Grotesk",system-ui', fontWeight:700, fontSize:14, color:'var(--muted)' }}>
              {Object.keys(matched).length/2} / {ex.pairs.length} matched
            </div>
          : <Feedback status="correct" title="All matched!" sub="Nicely done." onNext={() => onNext(true)} />}
      </div>
    );
  }

  /* ---- 5 · Speaking --------------------------------------------- */
  function SpeakExercise({ ex, onNext }) {
    const [phase, setPhase] = useState('ready'); // ready · listening · scored
    const [score] = useState(() => 88 + Math.floor(Math.random()*10));
    const play = () => speak(ex.item.ru);
    useEffect(() => { const id=setTimeout(play, 350); return ()=>clearTimeout(id); }, []); // eslint-disable-line
    const record = () => {
      setPhase('listening');
      setTimeout(() => setPhase('scored'), 1700);
    };
    return (
      <div style={{ display:'flex', flexDirection:'column', height:'100%' }}>
        <div style={{ flex:1, overflowY:'auto', padding:'4px 18px 20px' }}>
          <Prompt>{ex.prompt}</Prompt>
          <div style={{ marginBottom:24 }}><StackedGloss item={ex.item} compact /></div>

          <div style={{ display:'flex', flexDirection:'column', alignItems:'center', gap:14, paddingTop:6 }}>
            {phase !== 'scored' ? (
              <button onClick={record} disabled={phase==='listening'}
                style={{ appearance:'none', border:'none', cursor:phase==='listening'?'default':'pointer',
                  width:96, height:96, borderRadius:999,
                  background: phase==='listening'?NO:'var(--ink)', color:'#fff',
                  display:'flex', alignItems:'center', justifyContent:'center', position:'relative',
                  boxShadow:'0 14px 30px -14px rgba(0,0,0,0.5)', transition:'background .2s' }}>
                {phase==='listening' && <span style={{ position:'absolute', inset:-7, borderRadius:999,
                  border:`3px solid ${NO}`, opacity:0.4, animation:'ping 1.1s ease-out infinite' }}/>}
                <svg width="34" height="34" viewBox="0 0 24 24">
                  <rect x="9" y="3" width="6" height="11" rx="3" fill="#fff"/>
                  <path d="M5 11a7 7 0 0014 0M12 18v3" stroke="#fff" strokeWidth="2" fill="none" strokeLinecap="round"/>
                </svg>
              </button>
            ) : (
              <Ring size={96} stroke={8} value={score/100} color={OK}>
                <div style={{ textAlign:'center' }}>
                  <div style={{ fontFamily:'"Bricolage Grotesque",system-ui', fontWeight:800, fontSize:26, color:'var(--ink)' }}>{score}</div>
                  <div style={{ fontFamily:'"JetBrains Mono",monospace', fontSize:9, color:'var(--muted)', letterSpacing:'0.1em' }}>SCORE</div>
                </div>
              </Ring>
            )}
            <div style={{ fontFamily:'"Hanken Grotesk",system-ui', fontWeight:700, fontSize:14.5,
              color: phase==='scored'?OK:'var(--muted)', minHeight:20 }}>
              {phase==='ready' && 'Tap to speak'}
              {phase==='listening' && 'Listening…'}
              {phase==='scored' && 'Great pronunciation!'}
            </div>
            <button onClick={play} style={{ appearance:'none', border:'none', background:'transparent',
              cursor:'pointer', display:'flex', alignItems:'center', gap:7, color:'var(--primary-deep)',
              fontFamily:'"Hanken Grotesk",system-ui', fontWeight:700, fontSize:13.5 }}>
              <Speaker size={16} color="var(--primary-deep)" /> Hear native speaker
            </button>
          </div>
        </div>
        {phase==='scored' &&
          <Feedback status="correct" title="Sounds great!" sub="Your pronunciation matched closely." onNext={() => onNext(true)} />}
        {phase!=='scored' &&
          <div style={{ padding:'10px 18px calc(16px + env(safe-area-inset-bottom))', borderTop:'1px solid var(--line)' }}>
            <Btn variant="ghost" full onClick={() => onNext(true)}>Skip for now</Btn>
          </div>}
      </div>
    );
  }

  Object.assign(window, { LearnCard, ChoiceExercise, ListenExercise, MatchExercise, SpeakExercise, Feedback });
})();
