// ═════════════════════════════════════════════════════════════════════════════
// MindForge · Layer 3 · ui/ui.jsx
// ─────────────────────────────────────────────────────────────────────────────
// Role     : Shared visual primitives consumed by play screens AND the editor.
//            CardArt, QHeader, OptionRow, Waveform, XPFloat, Sparkles,
//            useIsMobile.
// Loaded   : #5
// Reads    : window.{ React, MF, cardPlaceholderBg, comboMult }
// Exposes  : window.{ CardArt, QHeader, OptionRow, Waveform, XPFloat,
//            Sparkles, useIsMobile }
// See also : docs/ARCHITECTURE.md §"UI conventions"
// ═════════════════════════════════════════════════════════════════════════════
//
// MindForge — shared UI components (legacy header preserved below)

const { useState, useEffect, useRef, useMemo, useCallback } = React;

// Live viewport-width breakpoint hook.
const useIsMobile = (breakpoint = 768) => {
  const get = () => typeof window !== 'undefined' && window.innerWidth < breakpoint;
  const [m, setM] = useState(get);
  useEffect(() => {
    const on = () => setM(get());
    window.addEventListener('resize', on);
    return () => window.removeEventListener('resize', on);
  }, [breakpoint]);
  return m;
};

// ─────────────── Card art (technique image or styled placeholder) ───────────────
// `blind` (used by the image-identification quiz) suppresses every text overlay
// that would reveal the card's identity — category, hangul, romaja and id.
const CardArt = ({ card, size = 'lg', blind = false }) => {
  const sizes = {
    sm: { p: 12, kr: 24, fr: 9 },
    md: { p: 18, kr: 44, fr: 11 },
    lg: { p: 22, kr: 68, fr: 12 },
  };
  const s = sizes[size];
  const hasPhoto = !!card.photo;
  const photoShadow = hasPhoto ? '0 1px 4px rgba(0,0,0,.6)' : 'none';
  return (
    <div style={{
      position:'relative', width:'100%', height:'100%',
      background: hasPhoto
        ? `${cardPlaceholderBg(card.tone)}`
        : cardPlaceholderBg(card.tone),
      borderRadius: 14, overflow:'hidden',
      display:'flex', flexDirection:'column', justifyContent:'space-between',
      padding: s.p, color:'#fff',
    }}>
      {hasPhoto && (
        <img src={card.photo} alt="" style={{
          position:'absolute', inset: 0, width:'100%', height:'100%', objectFit:'cover', zIndex: 0,
        }}/>
      )}
      {hasPhoto ? (
        /* Photo: darken corners for legibility of overlaid text */
        <div style={{position:'absolute', inset:0, zIndex: 0,
          background:'linear-gradient(180deg, rgba(0,0,0,.35) 0%, rgba(0,0,0,0) 30%, rgba(0,0,0,0) 60%, rgba(0,0,0,.65) 100%)',
        }}/>
      ) : (
        /* No photo: decorative dot pattern */
        <svg style={{position:'absolute',inset:0,opacity:.18}} width="100%" height="100%">
          <defs>
            <pattern id={`p${card.id}`} width="14" height="14" patternUnits="userSpaceOnUse">
              <circle cx="2" cy="2" r="1" fill="#fff"/>
            </pattern>
          </defs>
          <rect width="100%" height="100%" fill={`url(#p${card.id})`}/>
        </svg>
      )}
      {!blind && (
        <div style={{display:'flex',justifyContent:'space-between',alignItems:'center',position:'relative',zIndex:1}}>
          <span style={{fontSize: s.fr, letterSpacing:'.14em', textTransform:'uppercase', opacity:.75, fontWeight:600, textShadow: photoShadow}}>{card.cat}</span>
          <span style={{fontSize: s.fr, opacity:.65, fontFamily: MF.mono, textShadow: photoShadow}}>#{String(card.id).padStart(2,'0')}</span>
        </div>
      )}
      {!hasPhoto && !blind && (
        <div style={{position:'relative',zIndex:1,display:'flex',justifyContent:'center',alignItems:'center',flex:1}}>
          <span className="mf-kr" style={{fontSize: s.kr, fontWeight:700, letterSpacing:'-.02em', textShadow:'0 2px 24px rgba(0,0,0,.3)'}}>{card.kr}</span>
        </div>
      )}
      {!blind && (
        <div style={{position:'relative',zIndex:1,fontSize:s.fr+1,opacity:.95,fontWeight:600, textShadow: photoShadow}}>{card.ro}</div>
      )}
    </div>
  );
};

// ─────────────── Top header with progress + combo + lives ───────────────
const QHeader = ({ idx, total, combo, lives, onClose, mode }) => {
  const pct = (idx / total) * 100;
  const mult = comboMult(combo);
  return (
    <div style={{ padding: '4px 18px 12px' }}>
      <div style={{ display:'flex', alignItems:'center', gap: 12 }}>
        <button onClick={onClose} className="mf-tap" style={{
          width:34,height:34,borderRadius:10,border:`1px solid ${MF.line}`,background:MF.card,
          color:MF.textDim,fontSize:18,fontWeight:300,padding:0,display:'flex',alignItems:'center',justifyContent:'center'
        }}>✕</button>
        <div style={{
          flex:1, height:8, borderRadius:99, background:MF.card, overflow:'hidden', position:'relative',
          border:`1px solid ${MF.line}`
        }}>
          <div style={{
            position:'absolute', left:0, top:0, bottom:0,
            width: pct + '%', background:`linear-gradient(90deg, ${MF.purpleDim}, ${MF.purple})`,
            borderRadius:99, transition:'width .4s cubic-bezier(.2,.7,.3,1)'
          }}/>
        </div>
        {mode === 'survival' ? (
          <div style={{ display:'flex', gap: 4 }}>
            {[0,1,2].map(i => (
              <span key={i} style={{
                width:18,height:18,color: i < lives ? MF.bad : MF.line2,
                fontSize:18,lineHeight:'18px',transition:'color .3s'
              }}>♥</span>
            ))}
          </div>
        ) : (
          <span style={{ fontSize: 13, color: MF.textDim, fontWeight: 600, fontVariantNumeric:'tabular-nums', minWidth: 36, textAlign:'right' }}>{idx}/{total}</span>
        )}
      </div>

      {combo >= 2 && (
        <div className="mf-fade-up" style={{
          marginTop: 12, padding:'8px 14px',
          background: `linear-gradient(90deg, ${MF.card}, ${MF.card2})`,
          border:`1px solid ${MF.purple}`,
          borderRadius:99, display:'flex', alignItems:'center', gap: 10
        }}>
          <span style={{fontSize:11,letterSpacing:'.18em',color:MF.purple,fontWeight:700}}>COMBO</span>
          <div style={{flex:1,height:5,background:'rgba(167,139,250,.18)',borderRadius:99,overflow:'hidden',position:'relative'}}>
            <div style={{position:'absolute',inset:0,width: Math.min(100, combo*12) + '%', background:MF.purple, borderRadius:99}}/>
          </div>
          <span style={{fontSize:14,fontWeight:800,color:MF.purple,fontVariantNumeric:'tabular-nums'}}>×{mult}</span>
        </div>
      )}
    </div>
  );
};

// ─────────────── MC option button ───────────────
const OptionRow = ({ option, state, kbd, onPick, primary, sub, big }) => {
  // states: 'idle' 'selected' 'correct' 'wrong' 'dim'
  const colors = {
    idle:     { bg: MF.card,   border: MF.line,   text: MF.text,    sub: MF.textDim, shadow: 'none' },
    selected: { bg: MF.card2,  border: MF.purple, text: MF.text,    sub: MF.textDim, shadow: `0 0 0 1px ${MF.purple}` },
    correct:  { bg: 'rgba(116,216,161,.12)', border: MF.good, text: MF.good, sub: MF.good, shadow: `0 0 0 1px ${MF.good}, 0 6px 18px rgba(116,216,161,.18)` },
    wrong:    { bg: 'rgba(244,138,138,.10)', border: MF.bad,  text: MF.bad,  sub: MF.bad,  shadow: `0 0 0 1px ${MF.bad}` },
    dim:      { bg: MF.card,   border: MF.line,   text: MF.textMute, sub: MF.textMute, shadow: 'none' },
  };
  const c = colors[state] || colors.idle;
  return (
    <button
      className={`mf-tap ${state==='wrong' ? 'mf-shake' : ''} ${state==='correct' ? 'mf-pop':''}`}
      onClick={state==='idle' ? onPick : undefined}
      style={{
        width:'100%', display:'flex', alignItems:'center', gap: 14,
        padding: big ? '18px 16px' : '14px 14px',
        background: c.bg, border:`1.5px solid ${c.border}`, borderRadius: 14,
        color: c.text, textAlign:'left', cursor: state==='idle' ? 'pointer':'default',
        boxShadow: c.shadow, transition:'all .2s ease',
      }}
    >
      {kbd && (
        <span style={{
          minWidth: big ? 32 : 28, height: big ? 32 : 28, borderRadius: 8,
          border:`1.2px solid ${state==='idle' ? MF.line2 : c.border}`,
          background: state==='idle' ? MF.bg2 : 'transparent',
          color: state==='idle' ? MF.textDim : c.text,
          display:'flex',alignItems:'center',justifyContent:'center',
          fontFamily: MF.mono, fontSize: 13, fontWeight: 600,
        }}>{kbd}</span>
      )}
      <span style={{flex:1, display:'flex', flexDirection:'column', gap: 2, minWidth: 0}}>
        <span style={{fontSize: big ? 17 : 16, fontWeight: 600, overflowWrap:'anywhere', lineHeight: 1.3}}>{option}</span>
        {sub && <span className="mf-kr" style={{fontSize: 13, color: c.sub, fontWeight:500, overflowWrap:'anywhere'}}>{sub}</span>}
      </span>
      {state==='correct' && <span style={{fontSize:20,color:MF.good}}>✓</span>}
      {state==='wrong'   && <span style={{fontSize:20,color:MF.bad}}>✕</span>}
    </button>
  );
};

// ─────────────── Waveform player (faked) ───────────────
const Waveform = ({ playing, big }) => {
  const bars = 36;
  return (
    <svg width="100%" height={big ? 56 : 36} viewBox={`0 0 ${bars*6} ${big ? 56 : 36}`} preserveAspectRatio="none">
      {Array.from({length: bars}).map((_,i) => {
        const seed = Math.sin(i * 0.6) * 0.5 + Math.sin(i * 1.4) * 0.3 + 0.7;
        const h = (big ? 50 : 32) * (0.2 + Math.abs(seed) * 0.8);
        const active = playing && i < bars * 0.6;
        return (
          <rect
            key={i}
            x={i*6+1}
            y={(big ? 56 : 36)/2 - h/2}
            width="3" height={h} rx="1.5"
            fill={active ? MF.purple : MF.line2}
            style={{
              transition: 'fill .2s',
              animation: playing ? `mf-pop .${4+(i%6)}s ease-in-out infinite alternate` : 'none',
              transformOrigin: `${i*6+2.5}px ${(big ? 56 : 36)/2}px`,
            }}
          />
        );
      })}
    </svg>
  );
};

// ─────────────── Floating XP badge ───────────────
const XPFloat = ({ amount, show }) => (
  <div style={{
    position:'absolute', left:'50%', top: 100,
    transform:'translateX(-50%)',
    pointerEvents:'none', zIndex: 20,
    animation: show ? 'mf-float-up 1.4s ease-out forwards' : 'none',
    opacity: 0,
  }} key={show}>
    <span style={{
      padding:'10px 18px', borderRadius: 99,
      background: `linear-gradient(135deg, ${MF.purple}, ${MF.purpleDim})`,
      color:'#1a0f2e', fontWeight:800, fontSize: 22,
      boxShadow:'0 8px 30px rgba(167,139,250,.4)',
      letterSpacing:'-.01em',
    }}>+ {amount} XP</span>
  </div>
);

// ─────────────── Confetti dots for summary ───────────────
const Sparkles = ({ n = 18 }) => (
  <div style={{position:'absolute',inset:0,pointerEvents:'none',overflow:'hidden'}}>
    {Array.from({length:n}).map((_,i)=>{
      const x = (i*37)%100; const y = (i*61)%80;
      const c = [MF.purple, MF.blue, MF.amber, MF.good][i%4];
      return <span key={i} style={{
        position:'absolute', left:x+'%', top:y+'%',
        width:6,height:6,borderRadius:99,background:c,
        boxShadow:`0 0 10px ${c}`,
        animation:`mf-pop .${5+(i%4)}s ease-in-out ${i*60}ms both, mf-blink 2.${i%6}s ease-in-out infinite`,
        opacity:.85,
      }}/>;
    })}
  </div>
);

Object.assign(window, { CardArt, QHeader, OptionRow, Waveform, XPFloat, Sparkles, useIsMobile });
