'use client';

import { useLayoutEffect, useRef, type RefObject } from 'react';

const MOVE_MS = 700;
const ENTER_MS = 450;

function prefersReducedMotion(): boolean {
  return typeof window !== 'undefined' && window.matchMedia('(prefers-reduced-motion: reduce)').matches;
}

/**
 * FLIP list animation: children marked `data-flip-key` glide from their previous position to the
 * new one whenever `layoutKey` changes (rank shuffles). Positions use offsetTop — layout pixels on
 * the stage canvas, unaffected by the stage's scale transform. New rows fade in. Skipped entirely
 * when reduced motion is requested.
 */
export function useFlip(containerRef: RefObject<HTMLElement | null>, layoutKey: string): void {
  const positions = useRef<Map<string, number> | null>(null);

  useLayoutEffect(() => {
    const container = containerRef.current;
    if (!container) return;
    const previous = positions.current;
    const next = new Map<string, number>();
    const reduce = prefersReducedMotion();
    for (const item of container.querySelectorAll<HTMLElement>('[data-flip-key]')) {
      const key = item.dataset.flipKey;
      if (!key) continue;
      const top = item.offsetTop;
      next.set(key, top);
      if (!previous || reduce || typeof item.animate !== 'function') continue;
      const before = previous.get(key);
      if (before === undefined) {
        item.animate([{ opacity: 0, transform: 'translateY(16px)' }, { opacity: 1, transform: 'none' }], {
          duration: ENTER_MS,
          easing: 'cubic-bezier(0.2, 0.8, 0.2, 1)',
          fill: 'backwards',
        });
      } else if (before !== top) {
        item.animate([{ transform: `translateY(${before - top}px)` }, { transform: 'none' }], {
          duration: MOVE_MS,
          easing: 'cubic-bezier(0.2, 0.8, 0.2, 1)',
        });
      }
    }
    positions.current = next;
  }, [containerRef, layoutKey]);
}
