// Haptics + micro-animation helpers (ported from the mobile redesign handoff).
//
// Web haptics = the Vibration API (navigator.vibrate), which fires on Android
// Chrome and installed PWAs. iOS Safari has NO web Taptic API, so we also emit a
// tiny visual "tick" (a 1-frame scale pulse on the pressed element) so feedback
// reads on every device. Patterns are short and soft — comfort, not noise.
// Shared via window (no-build, in-browser Babel). Gate behind the Haptics setting.

const HAPTIC_PATTERNS = {
  selection: 6,                    // tab change, segmented pick, toggle
  light:     10,                   // option pick, "I don't know"
  medium:    18,                   // primary CTA press (Check / Begin / Next)
  success:   [13, 55, 20],         // correct answer — soft double tap
  error:     [26, 45, 26],         // wrong answer — two firmer pulses
  celebrate: [10, 40, 10, 40, 26], // streak milestone / session complete
};

let HAPTICS_ON = true;
function setHapticsEnabled(v) { HAPTICS_ON = !!v; }

function haptic(type = "selection") {
  if (!HAPTICS_ON) return;
  const pat = HAPTIC_PATTERNS[type] != null ? HAPTIC_PATTERNS[type] : HAPTIC_PATTERNS.selection;
  try { if (navigator.vibrate) navigator.vibrate(pat); } catch (e) {}
}

// Visual tick — the iOS-safe surrogate. Adds a class that CSS animates.
function visualTick(el) {
  if (!el) return;
  el.classList.remove("is-ticking");
  void el.offsetWidth; // force reflow so the animation restarts on rapid taps
  el.classList.add("is-ticking");
}

// tapFeedback — call from onClick: fires haptic + visual tick together.
function tapFeedback(type, e) {
  haptic(type);
  if (e && e.currentTarget) visualTick(e.currentTarget);
}

// <Pop> — animates a numeric/string value with a spring "bump" when it changes.
function Pop({ value, className = "" }) {
  const [bump, setBump] = React.useState(false);
  const prev = React.useRef(value);
  React.useEffect(() => {
    if (prev.current !== value) {
      prev.current = value;
      setBump(true);
      const t = setTimeout(() => setBump(false), 360);
      return () => clearTimeout(t);
    }
  }, [value]);
  return <span className={`${className} ${bump ? "is-bump" : ""}`}>{value}</span>;
}

// useCountUp — eases a number toward its target (used for the score).
function useCountUp(target, ms = 480) {
  const [n, setN] = React.useState(target);
  const from = React.useRef(target);
  const raf = React.useRef(0);
  React.useEffect(() => {
    const start = performance.now();
    const a = from.current, b = target;
    if (a === b) return;
    const tick = (t) => {
      const p = Math.min(1, (t - start) / ms);
      const eased = 1 - Math.pow(1 - p, 3); // easeOutCubic
      setN(Math.round(a + (b - a) * eased));
      if (p < 1) raf.current = requestAnimationFrame(tick);
      else from.current = b;
    };
    raf.current = requestAnimationFrame(tick);
    // fallback: if rAF is throttled (backgrounded tab), still land on the target
    const fb = setTimeout(() => { setN(b); from.current = b; }, ms + 80);
    return () => { cancelAnimationFrame(raf.current); clearTimeout(fb); };
  }, [target, ms]);
  return n;
}

Object.assign(window, { haptic, setHapticsEnabled, visualTick, tapFeedback, Pop, useCountUp });
