import { defineTrait } from '../define.js';

export const springAnimate = defineTrait({
  name: 'spring-animate',
  category: 'animation-feedback',
  description: 'Spring-based motion transitions',
  attributes: ['data-spring-animate-active'],
  events: [],
  config: ['data-spring-stiffness', 'data-spring-damping'],
  setup({ host }) {
    const stiffness = parseFloat(host.getAttribute('data-spring-stiffness')) || 180;
    const damping = parseFloat(host.getAttribute('data-spring-damping')) || 12;

    let rafId = null;
    const target = 0;

    // Read current translate as starting position. The trait writes to
    // `style.translate` (not `transform`), so read that first; fall back to
    // the transform matrix for callers that nudged via `transform`.
    const cs = getComputedStyle(host);
    let position = parseFloat(cs.translate) || 0;
    if (!position) {
      const matrix = new DOMMatrixReadOnly(cs.transform);
      position = matrix.m41 || 0;
    }
    let velocity = 0;

    host.setAttribute('data-spring-animate-active', '');

    let lastTime = performance.now();

    function tick(now) {
      const dt = Math.min((now - lastTime) / 1000, 0.064);
      lastTime = now;

      const displacement = position - target;
      const springForce = -stiffness * displacement;
      const dampingForce = -damping * velocity;
      const acceleration = springForce + dampingForce;

      velocity += acceleration * dt;
      position += velocity * dt;

      host.style.translate = `${position}px 0`;

      if (Math.abs(velocity) < 0.1 && Math.abs(displacement) < 0.1) {
        host.style.translate = '0 0';
        host.removeAttribute('data-spring-animate-active');
        return;
      }

      rafId = requestAnimationFrame(tick);
    }

    rafId = requestAnimationFrame(tick);

    return () => {
      if (rafId) cancelAnimationFrame(rafId);
      host.style.translate = '';
      host.removeAttribute('data-spring-animate-active');
    };
  },
});
