import {
  useCallback,
  useEffect,
  useId,
  useRef,
  useState,
  type CSSProperties,
  type KeyboardEvent as ReactKeyboardEvent,
  type ReactNode,
} from 'react';
import { prefersReducedMotion } from './utils.js';

export interface TiltGalleryItem {
  /** Stable id — React key + aria-controls. */
  id: string;
  /** Body slot for the tile. */
  content: ReactNode;
  /** Optional caption rendered under the tile. */
  caption?: ReactNode;
}

export interface TiltGalleryProps {
  /** The tiles to render. */
  items: TiltGalleryItem[];
  /** Maximum tilt angle in degrees (each axis). Default 8. */
  maxTilt?: number;
  /** Width of each tile in px. Default 280. */
  tileWidth?: number;
  /** Height of each tile in px. Default 200. */
  tileHeight?: number;
  /** Gap between tiles in px. Default 16. */
  gap?: number;
  /** Bypass tilt + glare entirely — useful for tests / reduced-motion. */
  disableMotion?: boolean;
  /** Accessible label for the gallery region. */
  ariaLabel?: string;
  className?: string;
  style?: CSSProperties;
}

/**
 * `<TiltGallery>` — horizontally-scrolling gallery of `<TiltCard>`-style
 * tiles. Each tile tilts toward the cursor on hover; the gallery itself
 * supports keyboard arrow scrolling and respects
 * `prefers-reduced-motion` for the tilt effect.
 *
 * Wave 13.D.5. Multi-card sibling of the existing `<TiltCard>` — built
 * on the same cursor-tracking math but with a single React component
 * orchestrating the whole row.
 */
export function TiltGallery({
  items,
  maxTilt = 8,
  tileWidth = 280,
  tileHeight = 200,
  gap = 16,
  disableMotion,
  ariaLabel = 'Tilt gallery',
  className,
  style,
}: TiltGalleryProps) {
  const reduced = disableMotion ?? prefersReducedMotion();
  const railRef = useRef<HTMLDivElement>(null);
  const baseId = useId();

  const onArrow = useCallback(
    (e: ReactKeyboardEvent<HTMLDivElement>) => {
      const rail = railRef.current;
      if (!rail) return;
      if (e.key === 'ArrowRight') {
        e.preventDefault();
        rail.scrollBy({ left: tileWidth + gap, behavior: 'smooth' });
      } else if (e.key === 'ArrowLeft') {
        e.preventDefault();
        rail.scrollBy({ left: -(tileWidth + gap), behavior: 'smooth' });
      }
    },
    [tileWidth, gap],
  );

  return (
    <div
      ref={railRef}
      role="region"
      aria-label={ariaLabel}
      tabIndex={0}
      onKeyDown={onArrow}
      data-testid="bl-tilt-gallery"
      data-reduced={reduced ? 'true' : 'false'}
      className={className}
      style={{
        display: 'flex',
        gap,
        overflowX: 'auto',
        scrollSnapType: 'x mandatory',
        padding: 4,
        outline: 'none',
        ...style,
      }}
    >
      {items.map((item, i) => (
        <Tile
          key={item.id}
          id={`${baseId}-${i}`}
          item={item}
          maxTilt={maxTilt}
          width={tileWidth}
          height={tileHeight}
          reduced={reduced}
        />
      ))}
    </div>
  );
}

function Tile({
  id,
  item,
  maxTilt,
  width,
  height,
  reduced,
}: {
  id: string;
  item: TiltGalleryItem;
  maxTilt: number;
  width: number;
  height: number;
  reduced: boolean;
}) {
  const ref = useRef<HTMLDivElement>(null);
  const [tilt, setTilt] = useState<{ rx: number; ry: number; gx: number; gy: number }>({
    rx: 0,
    ry: 0,
    gx: 50,
    gy: 50,
  });

  useEffect(() => {
    if (reduced) return;
    const el = ref.current;
    if (!el) return;
    const onMove = (e: PointerEvent) => {
      const rect = el.getBoundingClientRect();
      const x = (e.clientX - rect.left) / rect.width; // 0..1
      const y = (e.clientY - rect.top) / rect.height;
      const ry = (x - 0.5) * 2 * maxTilt; // -max..max
      const rx = -(y - 0.5) * 2 * maxTilt;
      setTilt({ rx, ry, gx: x * 100, gy: y * 100 });
    };
    const onLeave = () => setTilt({ rx: 0, ry: 0, gx: 50, gy: 50 });
    el.addEventListener('pointermove', onMove);
    el.addEventListener('pointerleave', onLeave);
    return () => {
      el.removeEventListener('pointermove', onMove);
      el.removeEventListener('pointerleave', onLeave);
    };
  }, [reduced, maxTilt]);

  return (
    <figure
      data-testid="bl-tilt-gallery-tile"
      id={id}
      style={{
        flex: '0 0 auto',
        margin: 0,
        scrollSnapAlign: 'start',
        width,
        perspective: 800,
      }}
    >
      <div
        ref={ref}
        style={{
          position: 'relative',
          width,
          height,
          borderRadius: 16,
          border: '1px solid var(--bl-border, rgba(0,0,0,0.12))',
          background: 'var(--bl-surface-card, #fff)',
          overflow: 'hidden',
          transform: reduced
            ? undefined
            : `rotateX(${tilt.rx.toFixed(2)}deg) rotateY(${tilt.ry.toFixed(2)}deg)`,
          transition: reduced ? undefined : 'transform 160ms ease',
          willChange: reduced ? undefined : 'transform',
        }}
      >
        <div style={{ position: 'relative', width: '100%', height: '100%' }}>
          {item.content}
        </div>
        {!reduced && (
          <div
            aria-hidden="true"
            style={{
              position: 'absolute',
              inset: 0,
              pointerEvents: 'none',
              background: `radial-gradient(120px circle at ${tilt.gx}% ${tilt.gy}%, color-mix(in srgb, var(--bl-accent, #6366f1) 18%, transparent), transparent 70%)`,
              transition: 'background 120ms ease',
            }}
          />
        )}
      </div>
      {item.caption && (
        <figcaption
          style={{
            marginTop: 8,
            fontSize: 12,
            color: 'var(--bl-text-tertiary, #999)',
          }}
        >
          {item.caption}
        </figcaption>
      )}
    </figure>
  );
}
