import { BRUSH_CONFIG } from "./config";

/**
 * Spring-based pointer follower — gives the brush real inertia (accelerates
 * toward the pointer, keeps moving briefly after the pointer stops, slight
 * overshoot then settle) instead of snapping/lerping straight onto the
 * cursor. All plain mutable state (no React state, no allocation per
 * frame) — meant to live in a `useRef`/effect closure, stepped once per
 * animation frame.
 */
export interface PointerPhysicsState {
  /** Smoothed (rendered) position — this is what the brush actually draws at. */
  x: number;
  y: number;
  vx: number;
  vy: number;
  /** Raw target — the actual pointer/touch position, updated directly by input handlers. */
  targetX: number;
  targetY: number;
  /** Smoothed speed (px/frame) — used to derive stamp radius and spacing. */
  speed: number;
  active: boolean;
}

export function createPointerPhysics(): PointerPhysicsState {
  return { x: 0, y: 0, vx: 0, vy: 0, targetX: 0, targetY: 0, speed: 0, active: false };
}

export function setPointerTarget(state: PointerPhysicsState, x: number, y: number): void {
  state.targetX = x;
  state.targetY = y;
  state.active = true;
}

export function setPointerInactive(state: PointerPhysicsState): void {
  state.active = false;
}

/**
 * Advances the spring one frame (semi-implicit Euler): acceleration toward
 * the target scaled by `stiffness` (the lerp-like "catch-up rate"),
 * velocity carried over and decayed by `damping` (the inertia itself — a
 * slightly underdamped value here is what produces the small overshoot
 * when the pointer stops, per the davidwhyte.com-style reference feel).
 */
export function stepPointerPhysics(state: PointerPhysicsState): void {
  const { pointerStiffness, pointerDamping, velocitySmoothing } = BRUSH_CONFIG;

  const ax = (state.targetX - state.x) * pointerStiffness;
  const ay = (state.targetY - state.y) * pointerStiffness;
  state.vx = (state.vx + ax) * pointerDamping;
  state.vy = (state.vy + ay) * pointerDamping;
  state.x += state.vx;
  state.y += state.vy;

  const instantSpeed = Math.sqrt(state.vx * state.vx + state.vy * state.vy);
  state.speed = state.speed * (1 - velocitySmoothing) + instantSpeed * velocitySmoothing;
}
