// App shell: state + navigation + IG share card renderer.

function computeResult(answers) {
  // answers: array of option indices, one per question
  const scores = Object.fromEntries(TYPES.map(t => [t, 0]));
  answers.forEach((pick, qi) => {
    if (pick == null) return;
    const opt = QUESTIONS[qi].opts[pick];
    Object.entries(opt.score).forEach(([t,v]) => { scores[t] += v; });
  });
  // Tie-breaker: prefer the earliest encountered type in a canonical order.
  let bestKey = TYPES[0], bestVal = -1;
  TYPES.forEach(t => { if (scores[t] > bestVal) { bestVal = scores[t]; bestKey = t; } });
  return { key: bestKey, scores };
}

// Renders a 9:16 share card on canvas, returns data URL (PNG).
async function renderShareCard(wagashi) {
  const W = 1080, H = 1920;
  const canvas = document.createElement('canvas');
  canvas.width = W; canvas.height = H;
  const ctx = canvas.getContext('2d');

  // Background — warm cream with vignettes
  const bg = ctx.createRadialGradient(W*0.2, H*0.15, 100, W*0.5, H*0.5, W*1.1);
  bg.addColorStop(0, '#FDF5E8');
  bg.addColorStop(0.45, '#F5F1E8');
  bg.addColorStop(1, '#E8DCC4');
  ctx.fillStyle = bg; ctx.fillRect(0,0,W,H);

  // soft color wash corners
  const tintTL = ctx.createRadialGradient(W*0.1, H*0.05, 0, W*0.1, H*0.05, W*0.8);
  tintTL.addColorStop(0, 'rgba(247,212,220,0.5)');
  tintTL.addColorStop(1, 'rgba(247,212,220,0)');
  ctx.fillStyle = tintTL; ctx.fillRect(0,0,W,H);
  const tintBR = ctx.createRadialGradient(W*0.9, H*0.95, 0, W*0.9, H*0.95, W*0.8);
  tintBR.addColorStop(0, 'rgba(200,211,184,0.5)');
  tintBR.addColorStop(1, 'rgba(200,211,184,0)');
  ctx.fillStyle = tintBR; ctx.fillRect(0,0,W,H);

  // Paper texture (dots)
  ctx.save();
  for (let i=0;i<1800;i++){
    ctx.fillStyle = 'rgba(120,95,65,' + (Math.random()*0.05+0.02) + ')';
    ctx.beginPath();
    ctx.arc(Math.random()*W, Math.random()*H, Math.random()*1.6, 0, Math.PI*2);
    ctx.fill();
  }
  ctx.restore();

  // Inner frame
  ctx.strokeStyle = 'rgba(201,168,106,0.5)';
  ctx.lineWidth = 2;
  ctx.strokeRect(60, 60, W-120, H-120);
  ctx.strokeStyle = 'rgba(201,168,106,0.25)';
  ctx.lineWidth = 1;
  ctx.strokeRect(80, 80, W-160, H-160);

  // Top kicker
  ctx.fillStyle = '#A88548';
  ctx.font = '500 28px "Noto Serif JP", serif';
  ctx.textAlign = 'center';
  ctx.fillText('和 ·  WAGASHI  · 心理測驗', W/2, 170);

  ctx.fillStyle = '#8C7A66';
  ctx.font = '400 24px "Inter", sans-serif';
  ctx.fillText('YOUR WAGASHI SOUL', W/2, 220);

  // --- Render wagashi illustration: use SVG -> Image
  const svgEl = document.querySelector('#share-art svg');
  if (svgEl) {
    const clone = svgEl.cloneNode(true);
    clone.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
    clone.setAttribute('xmlns:xlink', 'http://www.w3.org/1999/xlink');
    const svgStr = new XMLSerializer().serializeToString(clone);
    const svgBlob = new Blob([svgStr], { type:'image/svg+xml;charset=utf-8' });
    const url = URL.createObjectURL(svgBlob);
    await new Promise((resolve, reject) => {
      const img = new Image();
      img.onload = () => {
        // Soft shadow
        ctx.save();
        ctx.shadowColor = 'rgba(80,55,30,0.22)';
        ctx.shadowBlur = 40;
        ctx.shadowOffsetY = 24;
        const size = 620;
        ctx.drawImage(img, (W-size)/2, 300, size, size);
        ctx.restore();
        URL.revokeObjectURL(url);
        resolve();
      };
      img.onerror = reject;
      img.src = url;
    });
  }

  // JP label
  ctx.fillStyle = '#A88548';
  ctx.font = '500 38px "Noto Serif JP", serif';
  ctx.textAlign = 'center';
  ctx.fillText(wagashi.jp, W/2, 1000);

  // Big name
  ctx.fillStyle = '#2B2118';
  ctx.font = '700 140px "Noto Serif TC", "Noto Serif JP", serif';
  ctx.fillText(wagashi.name, W/2, 1150);

  // Divider
  ctx.strokeStyle = 'rgba(120,95,65,0.4)';
  ctx.lineWidth = 1;
  ctx.beginPath(); ctx.moveTo(W/2-170, 1210); ctx.lineTo(W/2-60, 1210); ctx.stroke();
  ctx.beginPath(); ctx.moveTo(W/2+60, 1210); ctx.lineTo(W/2+170, 1210); ctx.stroke();
  ctx.fillStyle = '#8C7A66';
  ctx.font = '500 24px "Noto Serif JP", serif';
  ctx.fillText('品 · 性 · 格', W/2, 1218);

  // Poem lines
  ctx.fillStyle = '#5B4A3B';
  ctx.font = '400 36px "Noto Serif TC", serif';
  const lines = wagashi.poem.split('\n');
  let y = 1290;
  lines.forEach(l => {
    ctx.fillText(l, W/2, y);
    y += 60;
  });

  // Traits pills
  const traitBg = [
    { bg:'rgba(247,212,220,0.8)', fg:'#8C2F42', bd:'rgba(232,154,170,0.6)' },
    { bg:'rgba(200,211,184,0.8)', fg:'#4A5E3A', bd:'rgba(138,160,120,0.6)' },
    { bg:'rgba(247,229,184,0.8)', fg:'#7A5A1F', bd:'rgba(201,168,106,0.7)' },
  ];
  const pillY = 1600;
  ctx.font = '500 32px "Noto Serif TC", serif';
  const gap = 28;
  const widths = wagashi.traits.map(t => ctx.measureText(t).width + 60);
  const totalW = widths.reduce((a,b)=>a+b,0) + gap*(widths.length-1);
  let x = (W - totalW)/2;
  wagashi.traits.forEach((t, i) => {
    const w = widths[i], h = 72;
    const style = traitBg[i % traitBg.length];
    ctx.fillStyle = style.bg;
    const r = h/2;
    ctx.beginPath();
    ctx.moveTo(x+r, pillY);
    ctx.arcTo(x+w, pillY, x+w, pillY+h, r);
    ctx.arcTo(x+w, pillY+h, x, pillY+h, r);
    ctx.arcTo(x, pillY+h, x, pillY, r);
    ctx.arcTo(x, pillY, x+w, pillY, r);
    ctx.closePath();
    ctx.fill();
    ctx.strokeStyle = style.bd;
    ctx.lineWidth = 1.5;
    ctx.stroke();
    ctx.fillStyle = style.fg;
    ctx.textBaseline = 'middle';
    ctx.fillText(t, x + w/2, pillY + h/2 + 2);
    ctx.textBaseline = 'alphabetic';
    x += w + gap;
  });

  // Footer
  ctx.fillStyle = '#8C7A66';
  ctx.font = '500 26px "Inter", sans-serif';
  ctx.textAlign = 'center';
  ctx.fillText('你是哪一種和菓子？ — Which Wagashi Are You?', W/2, 1780);
  ctx.font = '400 22px "Inter", sans-serif';
  ctx.fillStyle = '#A88548';
  ctx.fillText('#和菓子心理測驗  #WagashiSoul', W/2, 1820);

  return canvas.toDataURL('image/png');
}

function App() {
  const [stage, setStage] = useState('landing'); // 'landing' | 'quiz' | 'result'
  const [idx, setIdx] = useState(0);
  const [answers, setAnswers] = useState(Array(QUESTIONS.length).fill(null));
  const [dir, setDir] = useState('fwd');
  const [shareUrl, setShareUrl] = useState(null);
  const [showShare, setShowShare] = useState(false);
  const [building, setBuilding] = useState(false);

  const total = QUESTIONS.length;
  const result = useMemo(() => {
    if (stage !== 'result') return null;
    const r = computeResult(answers);
    return WAGASHI[r.key];
  }, [stage, answers]);

  // Persist
  useEffect(() => {
    try {
      const saved = JSON.parse(localStorage.getItem('wagashi-state') || 'null');
      if (saved) {
        setStage(saved.stage || 'landing');
        setIdx(saved.idx || 0);
        setAnswers(saved.answers || Array(QUESTIONS.length).fill(null));
      }
    } catch(e){}
  }, []);
  useEffect(() => {
    localStorage.setItem('wagashi-state', JSON.stringify({ stage, idx, answers }));
  }, [stage, idx, answers]);

  const start = () => { setStage('quiz'); setIdx(0); setAnswers(Array(total).fill(null)); setDir('fwd'); };
  const pick = (optIdx) => {
    const next = [...answers]; next[idx] = optIdx; setAnswers(next);
    setTimeout(() => {
      if (idx < total - 1) { setDir('fwd'); setIdx(idx+1); }
      else { setStage('result'); }
    }, 280);
  };
  const back = () => {
    if (idx === 0) return;
    setDir('back'); setIdx(idx-1);
  };
  const restart = () => { setStage('landing'); setIdx(0); setAnswers(Array(total).fill(null)); };

  const handleShare = async () => {
    setBuilding(true);
    // wait a frame so the hidden SVG is mounted
    await new Promise(r => requestAnimationFrame(() => requestAnimationFrame(r)));
    try {
      const url = await renderShareCard(result);
      setShareUrl(url);
      setShowShare(true);
    } catch(e) { console.error(e); }
    setBuilding(false);
  };

  const downloadShare = () => {
    if (!shareUrl) return;
    const a = document.createElement('a');
    a.href = shareUrl; a.download = `wagashi-${result.key}.png`;
    document.body.appendChild(a); a.click(); a.remove();
  };

  return (
    <div className="stage">
      <div className="phone">
        <div className="screen">
          {stage === 'landing' && <Landing onStart={start}/>}
          {stage === 'quiz' && (
            <Quiz
              index={idx}
              total={total}
              question={QUESTIONS[idx]}
              selected={answers[idx]}
              onPick={pick}
              onBack={back}
              dir={dir}
            />
          )}
          {stage === 'result' && result && (
            <Result wagashi={result} onShare={handleShare} onRestart={restart}/>
          )}
        </div>
      </div>

      {/* hidden SVG for share-card rasterisation — WagashiArt already wraps <svg> */}
      {result && (
        <div id="share-art" style={{position:'fixed',left:-9999,top:-9999,width:600,height:600}}>
          <WagashiArt type={result.key} size={600}/>
        </div>
      )}

      {showShare && shareUrl && (
        <div className="modal" onClick={()=>setShowShare(false)}>
          <div className="modal-card" onClick={e=>e.stopPropagation()}>
            <h3 className="serif">你的和菓子之魂</h3>
            <p>長按圖片儲存，或下載後貼到 Instagram 限時動態。</p>
            <img src={shareUrl} alt="share card"/>
            <div className="modal-row">
              <button className="cta" onClick={downloadShare}>下載圖片</button>
              <button className="cta secondary" onClick={()=>setShowShare(false)}>關閉</button>
            </div>
          </div>
        </div>
      )}

      {building && (
        <div className="modal"><div className="modal-card">
          <p className="serif" style={{padding:40}}>正在繪製你的和菓子卡片…</p>
        </div></div>
      )}

    </div>
  );
}

ReactDOM.createRoot(document.getElementById('root')).render(<App/>);
