import { useEffect, useRef, type CSSProperties, type ReactNode } from 'react';
import { prefersReducedMotion } from './utils.js';

export interface SpotlightProps {
  /** Slot rendered inside the spotlight wrapper. */
  children: ReactNode;
  /** Spotlight radius in px. Default 320. */
  size?: number;
  /** Gradient center colour. Defaults to `var(--bl-accent)` with .22 alpha. */
  color?: string;
  /** Background base colour beneath the spotlight. Defaults to transparent. */
  baseColor?: string;
  /** Bypass motion entirely (renders static `baseColor`). */
  disableMotion?: boolean;
  className?: string;
  style?: CSSProperties;
}

/**
 * `<Spotlight>` — radial gradient that follows the pointer.
 *
 * Wraps any block; on `pointermove` the gradient centre tracks the cursor
 * via two CSS custom properties (`--bl-spot-x` / `--bl-spot-y`). The CSS
 * variable update is the cheapest possible re-paint trigger — no React
 * re-renders, no setState in the listener.
 *
 * Honours `prefers-reduced-motion` (renders the static base layer
 * with the spotlight pinned to the centre).
 *
 * @example
 * ```tsx
 * <Spotlight>
 *   <h1>Hover me</h1>
 * </Spotlight>
 * ```
 */
export function Spotlight({
  children,
  size = 320,
  color = 'color-mix(in srgb, var(--bl-accent, #6366f1) 22%, transparent)',
  baseColor = 'transparent',
  disableMotion,
  className,
  style,
}: SpotlightProps) {
  const ref = useRef<HTMLDivElement>(null);
  const reduced = disableMotion ?? prefersReducedMotion();

  useEffect(() => {
    if (reduced) return;
    const el = ref.current;
    if (!el) return;
    const onMove = (e: PointerEvent) => {
      const rect = el.getBoundingClientRect();
      el.style.setProperty('--bl-spot-x', `${e.clientX - rect.left}px`);
      el.style.setProperty('--bl-spot-y', `${e.clientY - rect.top}px`);
    };
    const onLeave = () => {
      el.style.removeProperty('--bl-spot-x');
      el.style.removeProperty('--bl-spot-y');
    };
    el.addEventListener('pointermove', onMove);
    el.addEventListener('pointerleave', onLeave);
    return () => {
      el.removeEventListener('pointermove', onMove);
      el.removeEventListener('pointerleave', onLeave);
    };
  }, [reduced]);

  return (
    <div
      ref={ref}
      data-testid="bl-spotlight"
      data-reduced={reduced ? 'true' : 'false'}
      className={className}
      style={
        {
          position: 'relative',
          background: baseColor,
          backgroundImage: reduced
            ? `radial-gradient(${size}px circle at 50% 50%, ${color}, transparent 60%)`
            : `radial-gradient(${size}px circle at var(--bl-spot-x, 50%) var(--bl-spot-y, 50%), ${color}, transparent 60%)`,
          transition: 'background 200ms ease',
          ...style,
        } as CSSProperties
      }
    >
      {children}
    </div>
  );
}
