/* ===== 共享:数据、出题、通用组件 ===== */

const MODULES = {
  add: { key:'add', name:'加法', op:'+', color:'var(--pink)',   soft:'var(--pink-lt)',   tip:'20以内 · 以5为基数', pal:'#FF6FA5' },
  sub: { key:'sub', name:'减法', op:'−', color:'var(--blue)',   soft:'var(--blue-lt)',   tip:'20以内 · 以5为基数', pal:'#45B7F5' },
  mul: { key:'mul', name:'乘法口诀', op:'×', color:'var(--purple)', soft:'var(--purple-lt)', tip:'九九乘法表 · 点阵图', pal:'#9B7BF0' },
  div: { key:'div', name:'除法', op:'÷', color:'var(--mint)',   soft:'var(--mint-lt)',   tip:'平均分一分', pal:'#34D1BF' },
};
const ORDER = ['add','sub','mul','div'];

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

function genProblem(m) {
  // 自适应:有掌握度数据时按弱项加权出题;否则(冷启动/未加载)走随机
  if (window.Mastery) {
    const p = Mastery.gen(m);
    if (p) return p;
  }
  let a, b, ans;
  if (m === 'add')      { a = rnd(1, 15); b = rnd(1, 20 - a); ans = a + b; }
  else if (m === 'sub') { a = rnd(3, 20); b = rnd(1, a - 1); ans = a - b; }
  else if (m === 'mul') { a = rnd(2, 9); b = rnd(2, 9); ans = a * b; }
  else                  { b = rnd(2, 9); ans = rnd(2, 9); a = b * ans; }
  return { m, a, b, ans, id: Math.random() };
}

function makeOptions(ans, m) {
  const set = new Set([ans]);
  let guard = 0;
  while (set.size < 4 && guard < 60) {
    guard++;
    const span = (m === 'mul' || m === 'div') ? rnd(-4, 4) : rnd(-3, 3);
    const d = ans + span;
    if (d >= 0 && d !== ans) set.add(d);
  }
  let n = Math.max(0, ans - 2);
  while (set.size < 4) { if (n !== ans && n >= 0) set.add(n); n++; }
  return shuffle([...set]);
}

function qSpeech(p) {
  const ops = { add:'加', sub:'减', mul:'乘', div:'除以' };
  return `${p.a} ${ops[p.m]} ${p.b} 等于几?`;
}

/* ---- 顶部条 ---- */
function Header({ title, color, onBack, right }) {
  return (
    <div style={{ display:'flex', alignItems:'center', gap:14, padding:'18px 22px', position:'relative', zIndex:5 }}>
      <button className="pill" onClick={() => { Sound.click(); onBack(); }}>
        <span style={{ fontSize:22 }}>‹</span> 返回
      </button>
      <div className="num" style={{ flex:1, textAlign:'center', fontSize:34, color: color || 'var(--ink)' }}>{title}</div>
      <div style={{ minWidth:96, display:'flex', justifyContent:'flex-end', gap:8 }}>{right}</div>
    </div>
  );
}

/* ---- 喇叭按钮 ---- */
function SpeakBtn({ text, color }) {
  return (
    <button className="pill" onClick={() => { Sound.init(); Sound.speak(text); }}
      style={{ padding:'10px 14px', color: color || 'var(--ink)' }} title="再听一遍">
      <span style={{ fontSize:24 }}>🔊</span>
    </button>
  );
}

/* ---- 麦克风按钮:孩子说出答案 ---- */
function MicBtn({ color, onResult, disabled }) {
  const { useState } = React;
  const [rec, setRec] = useState(false);
  // 浏览器不支持录音则不渲染(降级到点选)
  if (!(window.AIVoice && window.AIVoice.supported)) return null;

  async function go() {
    if (rec || disabled) return;
    Sound.click();
    setRec(true);
    const res = await AIVoice.listen();
    setRec(false);
    if (res && res.number != null) {
      onResult(res.number);
    } else {
      // 没听清:温柔提示,不打断流程
      Sound.speak(res && res.text ? '我没听清,再说一遍好吗?' : '我没听清,再说一遍好吗?');
    }
  }

  return (
    <button className={'pill' + (rec ? ' recording' : '')} onClick={go} disabled={disabled}
      style={{ padding:'10px 14px', color: rec ? '#fff' : (color || 'var(--ink)') }}
      title="说出答案">
      <span style={{ fontSize:24 }}>{rec ? '🔴' : '🎤'}</span>
    </button>
  );
}

/* ---- 算式卡 ---- */
function Equation({ p, answer, state }) {
  const M = MODULES[p.m];
  const col = state === 'right' ? 'var(--green)' : state === 'wrong' ? 'var(--coral)' : M.color;
  return (
    <div className="num" style={{ display:'flex', alignItems:'center', justifyContent:'center', gap:18,
      fontSize:'clamp(40px, 8vw, 74px)', color:'var(--ink)', lineHeight:1 }}>
      <span>{p.a}</span>
      <span style={{ color: M.color }}>{M.op}</span>
      <span>{p.b}</span>
      <span style={{ color:'var(--ink-soft)' }}>=</span>
      <span style={{ minWidth:'1.4em', textAlign:'center', color: col,
        background: answer != null ? 'transparent' : 'var(--paper)',
        borderRadius:18, padding: answer != null ? 0 : '0 .15em',
        boxShadow: answer != null ? 'none' : 'inset 0 0 0 4px rgba(74,59,107,.12)' }}>
        {answer != null ? answer : '?'}
      </span>
    </div>
  );
}

/* ---- 答案泡泡 ---- */
function Bubbles({ options, correct, chosen, revealed, triedWrong = [], onPick }) {
  const colors = ['var(--pink)','var(--blue)','var(--mint)','var(--orange)'];
  return (
    <div style={{ display:'grid', gridTemplateColumns:'repeat(4, 1fr)', gap:16, maxWidth:680, margin:'0 auto', width:'100%' }}>
      {options.map((o, i) => {
        const tried = triedWrong.includes(o);
        const isChosen = chosen === o;
        const solved = chosen === correct;
        const showRight = o === correct && (revealed || isChosen);
        let bg = colors[i % 4], style = {};
        let disabled = tried || revealed || solved;
        if (showRight) { bg = 'var(--green)'; }
        else if (isChosen) { bg = 'var(--coral)'; style.animation = 'shake .5s'; }
        else if (tried) { bg = 'var(--coral)'; style.opacity = 0.4; }
        else if (chosen != null || revealed) { style.opacity = 0.5; }
        return (
          <button key={i} className="btn num" disabled={disabled}
            onClick={() => { if (!disabled) onPick(o); }}
            style={{ background: bg, fontSize:'clamp(28px,5vw,44px)',
              padding:'18px 0', borderRadius:24, ...style }}>
            {o}
          </button>
        );
      })}
    </div>
  );
}

/* ---- 进度星星 ---- */
function Progress({ idx, total, results }) {
  return (
    <div style={{ display:'flex', gap:7, justifyContent:'center', flexWrap:'wrap', maxWidth:640, margin:'0 auto' }}>
      {Array.from({ length: total }).map((_, i) => {
        const r = results[i];
        const cur = i === idx;
        return (
          <div key={i} style={{ width:22, height:22, borderRadius:'50%',
            display:'flex', alignItems:'center', justifyContent:'center', fontSize:14,
            transform: cur ? 'scale(1.35)' : 'none', transition:'all .2s',
            background: r === true ? 'var(--green)' : r === false ? 'var(--coral)' : '#fff',
            boxShadow: cur ? '0 0 0 3px var(--yellow)' : 'inset 0 0 0 2px rgba(74,59,107,.12)',
            color:'#fff' }}>
            {r === true ? '✓' : r === false ? '✕' : ''}
          </div>
        );
      })}
    </div>
  );
}

Object.assign(window, {
  MODULES, ORDER, rnd, shuffle, genProblem, makeOptions, qSpeech,
  Header, SpeakBtn, MicBtn, Equation, Bubbles, Progress,
});
