// Arc-based move animator with overshoot bounce + particle burst
import { getPointCoords } from './board-renderer.js';

const MOVE_DURATION = 320;
const HIT_DURATION = 420;
const BEAR_DURATION = 380;

export function createMoveAnimation(from, to, layout, onFrame, onComplete) {
  const startPos = getPixelPos(from, layout);
  const endPos = getPixelPos(to, layout);

  if (!startPos || !endPos) { onComplete(); return; }

  const startTime = performance.now();
  const isHit = to === 'bar';
  const isBear = to === 'off';
  const duration = isHit ? HIT_DURATION : isBear ? BEAR_DURATION : MOVE_DURATION;

  // Arc height proportional to distance
  const dist = Math.hypot(endPos.x - startPos.x, endPos.y - startPos.y);
  const arcHeight = Math.min(dist * 0.4, 60);

  function tick(now) {
    const elapsed = now - startTime;
    const raw = Math.min(1, elapsed / duration);

    // Ease: overshoot for moves, bounce for hits
    const t = isHit ? easeOutBounce(raw) : easeOutBack(raw);

    const x = startPos.x + (endPos.x - startPos.x) * t;
    const y = startPos.y + (endPos.y - startPos.y) * t;

    // Parabolic arc
    const arcY = -arcHeight * 4 * raw * (1 - raw);

    // Scale pulse on landing
    const scale = raw > 0.85 ? 1 + (1 - raw) * 2 * 0.15 : 1;

    onFrame({ x, y: y + arcY, progress: raw, scale, isLanding: raw > 0.95 });

    if (raw < 1) {
      requestAnimationFrame(tick);
    } else {
      onComplete();
    }
  }
  requestAnimationFrame(tick);
}

export function createHitAnimation(hitPos, onFrame, onComplete) {
  const startTime = performance.now();
  const duration = 300;

  function tick(now) {
    const elapsed = now - startTime;
    const t = Math.min(1, elapsed / duration);
    const shake = Math.sin(t * Math.PI * 4) * (1 - t) * 6;
    const scale = 1 + Math.sin(t * Math.PI) * 0.3;
    onFrame({ shake, scale, progress: t });
    if (t < 1) requestAnimationFrame(tick);
    else onComplete();
  }
  requestAnimationFrame(tick);
}

export function createBearOffAnimation(pos, onFrame, onComplete) {
  const startTime = performance.now();
  const duration = 400;

  function tick(now) {
    const elapsed = now - startTime;
    const t = Math.min(1, elapsed / duration);
    const ease = easeOutCubic(t);
    const scale = 1 - ease * 0.6;
    const alpha = 1 - ease;
    const y = pos.y + ease * 30;
    onFrame({ x: pos.x, y, scale, alpha, progress: t });
    if (t < 1) requestAnimationFrame(tick);
    else onComplete();
  }
  requestAnimationFrame(tick);
}

function getPixelPos(location, layout) {
  if (!layout) return null;
  const { margin, pointW, pointH, barWidth, boardH, bearW, innerW, checkerR } = layout;
  const barX = margin + 6 * pointW;
  const bearX = margin + innerW;

  if (location === 'bar') return { x: barX + barWidth / 2, y: margin + boardH / 2 };
  if (location === 'off') return { x: bearX + bearW / 2, y: margin + boardH / 2 };

  if (typeof location === 'number' && location >= 0 && location <= 23) {
    const { x, y, isTop } = getPointCoords(location, margin, pointW, pointH, barWidth, boardH);
    return { x: x + pointW / 2, y: isTop ? y + checkerR * 2 : y - checkerR * 2 };
  }
  return null;
}

function easeOutBack(t) {
  const c1 = 1.70158;
  const c3 = c1 + 1;
  return 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2);
}

function easeOutBounce(t) {
  if (t < 1 / 2.75) return 7.5625 * t * t;
  if (t < 2 / 2.75) { t -= 1.5 / 2.75; return 7.5625 * t * t + 0.75; }
  if (t < 2.5 / 2.75) { t -= 2.25 / 2.75; return 7.5625 * t * t + 0.9375; }
  t -= 2.625 / 2.75;
  return 7.5625 * t * t + 0.984375;
}

function easeOutCubic(t) {
  return 1 - Math.pow(1 - t, 3);
}
