// exercise-info.jsx — exercise reference popup (description + animated demo)
// Imagery streamed from the public-domain free-exercise-db on GitHub:
// two frames per move (start / end) cross-faded for a simple animated demo.

// ── Store (lives outside React so any InfoButton can open the modal) ──
const ExerciseInfoStore = (function () {
  let current = null;
  const subs = new Set();
  return {
    get current() { return current; },
    open(id) { current = id; subs.forEach(f => f()); },
    close() { current = null; subs.forEach(f => f()); },
    subscribe(fn) { subs.add(fn); return () => subs.delete(fn); }
  };
})();
function openExerciseInfo(id) { haptic('light'); ExerciseInfoStore.open(id); try { window.history.pushState({ exerciseInfo: id }, ''); } catch(e) {} }

// ── Shared frame ticker ──────────────────────────────────────
// One interval drives every on-screen thumbnail's cross-fade in unison, so a
// long list of thumbnails costs a single timer (not one per row) and the motion
// reads as a calm, synchronized "breathing" rather than random strobing.
const ThumbTicker = (function () {
  let frame = 0;
  const subs = new Set();
  setInterval(() => {
    // Pause when the tab is hidden — no point animating off-screen.
    if (typeof document !== 'undefined' && document.hidden) return;
    frame ^= 1;
    subs.forEach((f) => f(frame));
  }, 1150);
  return { get: () => frame, sub: (fn) => { subs.add(fn); return () => subs.delete(fn); } };
})();

// Small animated exercise thumbnail — the same start/end demo frames as the
// info modal, shrunk down. Doubles as the "tap for info" affordance: the motion
// catches the eye and the little ⓘ badge signals it opens the exercise guide.
function ExerciseThumb({ id, size = 46, style = {} }) {
  const c = useTheme();
  const imgs = exImages(id);
  const [frame, setFrame] = React.useState(() => ThumbTicker.get());
  const [loaded, setLoaded] = React.useState(false);
  const [failed, setFailed] = React.useState(false);
  React.useEffect(() => ThumbTicker.sub(setFrame), []);
  React.useEffect(() => { setLoaded(false); setFailed(false); }, [id]);

  const has = imgs.length >= 1 && !failed;
  const animate = imgs.length >= 2 && !failed;
  const radius = Math.round(size * 0.26);
  const badge = Math.max(15, Math.round(size * 0.4));

  const open = (e) => { e.stopPropagation(); openExerciseInfo(id); };

  return (
    <button onClick={open} aria-label="Show exercise info"
      style={{ position: 'relative', width: size, height: size, flexShrink: 0, padding: 0, cursor: 'pointer',
        borderRadius: radius, overflow: 'hidden', border: '1px solid var(--border)',
        background: has ? '#FFFFFF' : `repeating-linear-gradient(135deg, ${c.surface2}, ${c.surface2} 6px, ${c.surface3} 6px, ${c.surface3} 12px)`,
        display: 'flex', alignItems: 'center', justifyContent: 'center', ...style }}>
      {has ? (
        imgs.slice(0, 2).map((src, i) => (
          <img key={src} src={src} alt="" loading="lazy" onError={() => setFailed(true)} onLoad={() => setLoaded(true)}
            style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'cover',
              opacity: loaded && (animate ? frame === i : i === 0) ? 1 : 0, transition: 'opacity .55s ease' }} />
        ))
      ) : (
        <Icon name="dumbbell" size={Math.round(size * 0.42)} style={{ color: 'var(--dim)' }} />
      )}
      {/* ⓘ badge — the discoverability cue that this opens more info */}
      <span style={{ position: 'absolute', right: -1, bottom: -1, width: badge, height: badge, borderRadius: 999,
        background: c.accent, color: c.accentInk, border: '2px solid var(--surface)',
        display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
        <Icon name="info" size={Math.round(badge * 0.62)} stroke={2.4} />
      </span>
    </button>
  );
}

// Small round "i" button — drop next to any exercise name.
function ExerciseInfoButton({ id, size = 34, style = {} }) {
  const c = useTheme();
  if (!exInfo(id)) return null; // only show where we have reference content
  return (
    <button onClick={(e) => { e.stopPropagation(); openExerciseInfo(id); }} aria-label="Exercise info"
      style={{ width: size, height: size, borderRadius: 999, flexShrink: 0, cursor: 'pointer',
        border: '1px solid var(--border)', background: 'var(--surface-2)', color: 'var(--muted)',
        display: 'flex', alignItems: 'center', justifyContent: 'center', ...style }}>
      <Icon name="info" size={Math.round(size * 0.56)} />
    </button>
  );
}

// Animated demo — cross-fades between the start/end frames every ~0.9s.
function ExerciseDemo({ id, height = 230 }) {
  const c = useTheme();
  const imgs = exImages(id);
  const [frame, setFrame] = React.useState(0);
  const [failed, setFailed] = React.useState(false);
  React.useEffect(() => {
    setFrame(0); setFailed(false);
    if (imgs.length < 2) return;
    const t = setInterval(() => setFrame(f => f ^ 1), 900);
    return () => clearInterval(t);
  }, [id]);

  if (failed || imgs.length === 0) {
    return (
      <div style={{ position: 'relative', height, borderRadius: c.radius, overflow: 'hidden', border: '1px solid var(--border)',
        background: `repeating-linear-gradient(135deg, ${c.surface2}, ${c.surface2} 11px, ${c.surface3} 11px, ${c.surface3} 22px)`,
        display: 'flex', alignItems: 'center', justifyContent: 'center', color: 'var(--dim)' }}>
        <Icon name="dumbbell" size={40} />
      </div>
    );
  }
  return (
    <div style={{ position: 'relative', height, borderRadius: c.radius, overflow: 'hidden', border: '1px solid var(--border)', background: '#FFFFFF' }}>
      {imgs.map((src, i) => (
        <img key={src} src={src} alt="" onError={() => setFailed(true)}
          style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', objectFit: 'contain',
            opacity: frame === i ? 1 : 0, transition: 'opacity .4s ease' }} />
      ))}
      <div style={{ position: 'absolute', left: 10, top: 10, display: 'flex', alignItems: 'center', gap: 6,
        padding: '5px 9px', borderRadius: 999, background: 'rgba(10,11,13,0.72)', backdropFilter: 'blur(4px)' }}>
        <span style={{ width: 7, height: 7, borderRadius: 999, background: c.accent, boxShadow: `0 0 8px ${c.accent}` }} />
        <span style={{ fontFamily: 'var(--font-body)', fontSize: 10, fontWeight: 800, letterSpacing: 1, textTransform: 'uppercase', color: '#fff' }}>Live demo</span>
      </div>
    </div>
  );
}

// The popup itself — mounted once at the app shell.
function ExerciseInfoModal() {
  const c = useTheme();
  const [id, setId] = React.useState(() => ExerciseInfoStore.current);
  React.useEffect(() => ExerciseInfoStore.subscribe(() => setId(ExerciseInfoStore.current)), []);
  React.useEffect(() => {
    if (!id) return;
    const onKey = (e) => { if (e.key === 'Escape') { try { window.history.back(); } catch(ex) { ExerciseInfoStore.close(); } } };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [id]);
  if (!id) return null;
  const ex = exById(id);
  const info = exInfo(id) || { desc: '', cues: [] };
  const close = () => { haptic('light'); try { window.history.back(); } catch(e) { ExerciseInfoStore.close(); } };

  return (
    <div style={{ position: 'absolute', inset: 0, zIndex: 60, display: 'flex', flexDirection: 'column', justifyContent: 'flex-end' }}>
      <div onClick={close} style={{ position: 'absolute', inset: 0, background: 'rgba(0,0,0,0.6)', animation: 'psyfade .2s ease' }} />
      <div style={{ position: 'relative', background: 'var(--surface)', borderTopLeftRadius: 28, borderTopRightRadius: 28,
        borderTop: '1px solid var(--border)', padding: '12px 20px 30px', maxHeight: '90%', overflowY: 'auto',
        animation: 'psyslide .28s cubic-bezier(.2,.8,.2,1)' }}>
        <div style={{ width: 40, height: 4, borderRadius: 999, background: 'var(--border)', margin: '0 auto 16px' }} />

        <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 12, marginBottom: 14 }}>
          <div style={{ minWidth: 0 }}>
            <Eyebrow style={{ marginBottom: 6 }}>{ex.muscle} · {ex.gear}</Eyebrow>
            <Display size={28} style={{ lineHeight: 1.02 }}>{ex.name}</Display>
          </div>
          <button onClick={close} aria-label="Close" style={{ width: 36, height: 36, borderRadius: 999, flexShrink: 0, cursor: 'pointer',
            border: '1px solid var(--border)', background: 'var(--surface-2)', color: 'var(--text)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <Icon name="close" size={18} />
          </button>
        </div>

        <ExerciseDemo id={id} />

        {(() => {
          const meta = [info.level, info.gear, info.mechanic ? titleCase(info.mechanic) : null,
            info.force && info.force !== 'static' ? titleCase(info.force) : (info.force === 'static' ? 'Static' : null)].filter(Boolean);
          return meta.length ? (
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 7, marginTop: 14 }}>
              {meta.map((m, i) => (
                <span key={i} style={{ fontFamily: 'var(--font-body)', fontSize: 11.5, fontWeight: 700, padding: '5px 11px', borderRadius: 999,
                  background: i === 0 ? c.accent : 'var(--surface-2)', color: i === 0 ? c.accentInk : 'var(--muted)', border: i === 0 ? 'none' : '1px solid var(--border)' }}>{m}</span>
              ))}
            </div>
          ) : null;
        })()}

        {info.desc && (
          <p style={{ fontFamily: 'var(--font-body)', fontSize: 14.5, lineHeight: 1.55, color: 'var(--text)', margin: '16px 0 0', textWrap: 'pretty' }}>{info.desc}</p>
        )}

        {info.cues && info.cues.length > 0 && (
          <div style={{ marginTop: 18 }}>
            <Eyebrow style={{ marginBottom: 11 }}>{window.EXERCISE_INFO && window.EXERCISE_INFO[id] ? 'Form cues' : 'How to perform'}</Eyebrow>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 9 }}>
              {info.cues.map((cue, i) => (
                <div key={i} style={{ display: 'flex', alignItems: 'flex-start', gap: 12 }}>
                  <span style={{ width: 24, height: 24, borderRadius: 7, flexShrink: 0, marginTop: 1, background: c.accent, color: c.accentInk,
                    fontFamily: 'var(--font-display)', fontSize: 13, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>{i + 1}</span>
                  <span style={{ fontFamily: 'var(--font-body)', fontSize: 14, fontWeight: 600, lineHeight: 1.45, color: 'var(--text)' }}>{cue}</span>
                </div>
              ))}
            </div>
          </div>
        )}

        {(info.primary.length > 0 || info.secondary.length > 0) && (
          <div style={{ marginTop: 18 }}>
            <Eyebrow style={{ marginBottom: 11 }}>Muscles worked</Eyebrow>
            <div style={{ display: 'flex', flexWrap: 'wrap', gap: 7 }}>
              {info.primary.map((m) => (
                <span key={'p' + m} style={{ fontFamily: 'var(--font-body)', fontSize: 12, fontWeight: 700, padding: '5px 11px', borderRadius: 999,
                  background: c.accent + '1F', color: c.accent, border: `1px solid ${c.accent}55` }}>{titleCase(m)}</span>
              ))}
              {info.secondary.map((m) => (
                <span key={'s' + m} style={{ fontFamily: 'var(--font-body)', fontSize: 12, fontWeight: 600, padding: '5px 11px', borderRadius: 999,
                  background: 'var(--surface-2)', color: 'var(--muted)', border: '1px solid var(--border)' }}>{titleCase(m)}</span>
              ))}
            </div>
          </div>
        )}

        <div style={{ marginTop: 20, fontFamily: 'var(--font-body)', fontSize: 11, color: 'var(--dim)', lineHeight: 1.5 }}>
          Demo imagery & instructions from the public-domain free-exercise-db.
        </div>
      </div>
    </div>
  );
}

// Three scrolling chip rows: Muscle / Gear / Level. `value` is { muscle, equip, level }.
function ExerciseFacets({ value, onChange }) {
  const rows = [
    ['Muscle', 'muscle', MUSCLES],
    ['Gear', 'equip', EQUIPMENT_FILTERS],
    ['Level', 'level', LEVEL_FILTERS],
  ];
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
      {rows.map(([label, key, opts]) => (
        <div key={key} style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <span style={{ width: 44, flexShrink: 0, fontFamily: 'var(--font-body)', fontSize: 10, fontWeight: 800, letterSpacing: 0.6, textTransform: 'uppercase', color: 'var(--dim)' }}>{label}</span>
          <div style={{ display: 'flex', gap: 7, overflowX: 'auto', padding: '1px 0', margin: '0 -20px', paddingLeft: 0, paddingRight: 20 }}>
            {['All', ...opts].map((o) => (
              <Chip key={o} active={(value[key] || 'All') === o} onClick={() => onChange({ ...value, [key]: o })}>{o}</Chip>
            ))}
          </div>
        </div>
      ))}
    </div>
  );
}

Object.assign(window, { ExerciseInfoStore, openExerciseInfo, ExerciseInfoButton, ExerciseThumb, ExerciseDemo, ExerciseInfoModal, ExerciseFacets });
