/* ════════════════════════════════════════════════════════════
   P2 gesture primitives + P10 state primitives
   - <Swipeable> rubber-band swipe with reveal
   - <PeekPress> long-press → Apple Peek/Pop preview
   - <PullToRefresh> drag-down refresh
   - <Skeleton> Apple shimmer
   - <EmptyState> centered icon + CTA
   - <ErrorBar> top capsule banner
   ════════════════════════════════════════════════════════════ */

const { useState: gs_s, useEffect: gs_e, useRef: gs_r } = React;

function Swipeable({ children, leftActions = [], rightActions = [], onCommit }) {
  const [dx, setDx] = gs_s(0);
  const [committed, setCommitted] = gs_s(false);
  const startX = gs_r(0);
  const dragging = gs_r(false);
  const lastFired = gs_r(null);
  const MAX = 140;

  const onDown = (e) => { startX.current = e.clientX; dragging.current = true; };
  const onMove = (e) => {
    if (!dragging.current) return;
    let raw = e.clientX - startX.current;
    // rubber-band past MAX
    const sign = Math.sign(raw);
    const mag = Math.abs(raw);
    const dampened = mag > MAX ? MAX + (mag - MAX) * 0.32 : mag;
    setDx(sign * dampened);
    // hit thresholds for haptic
    const threshold = MAX * 0.55;
    const stage = mag > threshold ? sign : 0;
    if (stage !== lastFired.current) {
      window.haptic?.[stage === 0 ? 'selection' : 'medium']();
      lastFired.current = stage;
    }
  };
  const onUp = () => {
    if (!dragging.current) return;
    dragging.current = false;
    if (Math.abs(dx) > MAX * 0.55) {
      const dir = dx > 0 ? 'right' : 'left';
      window.haptic?.success();
      setCommitted(true);
      setDx(dx > 0 ? 360 : -360);
      onCommit?.(dir);
      setTimeout(() => { setCommitted(false); setDx(0); lastFired.current = null; }, 600);
    } else {
      setDx(0);
      lastFired.current = null;
    }
  };

  const acts = dx > 0 ? leftActions : dx < 0 ? rightActions : [];
  return (
    <div className="swipe-wrap">
      <div className={'swipe-tray ' + (dx > 0 ? 'left' : 'right')}>
        {acts.map((a, i) => (
          <div key={i} className="swipe-act" style={{ background: a.color }}>{a.icon}{a.label}</div>
        ))}
      </div>
      <div className="swipe-content"
           style={{ transform: `translateX(${dx}px)`, transition: dragging.current ? 'none' : `transform var(--dur-slow) var(--ease-spring-soft)`, opacity: committed ? 0.4 : 1 }}
           onPointerDown={onDown} onPointerMove={onMove}
           onPointerUp={onUp} onPointerCancel={onUp}>
        {children}
      </div>
    </div>
  );
}
window.Swipeable = Swipeable;

function PeekPress({ children, peek, onPop }) {
  const [phase, setPhase] = gs_s('idle'); // idle | peek | pop
  const timer = gs_r(null);
  const onDown = () => {
    timer.current = setTimeout(() => {
      setPhase('peek');
      window.haptic?.medium();
    }, 420);
  };
  const cancel = () => { if (timer.current) { clearTimeout(timer.current); timer.current = null; } };
  const onUp = () => {
    cancel();
    if (phase === 'peek') { setPhase('idle'); }
  };
  const popOpen = () => { window.haptic?.heavy(); setPhase('idle'); onPop?.(); };

  return (
    <>
      <div className="peek-trigger"
           style={{ transform: phase === 'peek' ? 'scale(0.97)' : 'scale(1)', transition: 'transform var(--dur-base) var(--ease-standard)' }}
           onPointerDown={onDown} onPointerUp={onUp} onPointerCancel={cancel}
           onContextMenu={(e) => { e.preventDefault(); setPhase('peek'); window.haptic?.medium(); }}>
        {children}
      </div>
      {phase === 'peek' && (
        <>
          <div className="peek-veil" onClick={() => setPhase('idle')}/>
          <div className="peek-card">
            <div className="peek-body">{peek}</div>
            <button className="peek-cta" onClick={popOpen}>Open →</button>
          </div>
        </>
      )}
    </>
  );
}
window.PeekPress = PeekPress;

function Skeleton({ w = '100%', h = 14, r = 4, style }) {
  return <div className="skel" style={{ width: w, height: h, borderRadius: r, ...style }}/>;
}
window.Skeleton = Skeleton;

function EmptyState({ glyph = '◌', title, hint, cta }) {
  return (
    <div className="empty-state">
      <div className="es-glyph">{glyph}</div>
      <div className="es-title">{title}</div>
      {hint && <div className="es-hint">{hint}</div>}
      {cta && <button className="es-cta" onClick={cta.run} data-haptic="medium">{cta.label}</button>}
    </div>
  );
}
window.EmptyState = EmptyState;

function ErrorBar({ msg, onRetry }) {
  const lang = window.__LANG || 'zh';
  return (
    <div className="err-bar">
      <span className="err-dot"/>
      <span className="err-msg">{msg}</span>
      {onRetry && <button className="err-retry" onClick={onRetry} data-haptic="medium">{lang==='zh'?'重试':'Retry'}</button>}
    </div>
  );
}
window.ErrorBar = ErrorBar;
