/**
 * useBackdropEffect Hook
 *
 * Enables backdrop-filter effects on elements inside CSS transform contexts.
 * Registers a backdrop layer in the BackdropPortal that renders outside the
 * transform hierarchy, allowing backdrop-filter to work properly.
 *
 * When BackdropPortalProvider is not available (e.g., standalone usage),
 * the hook gracefully degrades and returns `isPortalAvailable: false` so
 * the component can apply inline backdrop styles as fallback.
 *
 * Usage:
 * ```tsx
 * const { ref, isPortalAvailable } = useBackdropEffect({
 *   enabled: true,
 *   backdropFilter: 'blur(4px)',
 *   backgroundColor: 'rgba(0, 0, 0, 0.6)',
 *   borderRadius: '0.75rem',
 * });
 *
 * return (
 *   <div
 *     ref={ref}
 *     style={isPortalAvailable ? { backgroundColor: 'transparent' } : {
 *       backdropFilter: 'blur(4px)',
 *       backgroundColor: 'rgba(0, 0, 0, 0.6)',
 *     }}
 *   >
 *     Content
 *   </div>
 * );
 * ```
 */

import { useEffect, useLayoutEffect, useRef, useId, useCallback } from 'react';
import type { CSSProperties } from 'react';
import { useBackdropPortal } from '../components/BackdropPortal';

interface UseBackdropEffectOptions {
  /** Whether the backdrop effect is enabled */
  enabled: boolean;
  /** CSS backdrop-filter value (e.g., 'blur(4px)') */
  backdropFilter: string;
  /** Background color for the backdrop layer */
  backgroundColor: string;
  /** Border radius to match the element's shape */
  borderRadius?: string;
  /** Z-index for layering multiple backdrops */
  zIndex?: number;
}

interface UseBackdropEffectResult {
  /** Ref to attach to the element that should have the backdrop effect */
  ref: React.RefObject<HTMLDivElement | null>;
  /** Whether the portal is available (BackdropPortalProvider is present) */
  isPortalAvailable: boolean;
}

export function useBackdropEffect(
  options: UseBackdropEffectOptions,
): UseBackdropEffectResult {
  const {
    enabled,
    backdropFilter,
    backgroundColor,
    borderRadius,
    zIndex = 0,
  } = options;
  const id = useId();
  const elementRef = useRef<HTMLDivElement>(null);
  const backdropPortal = useBackdropPortal();
  const rafIdRef = useRef<number | null>(null);

  const isPortalAvailable = backdropPortal !== null;

  const updatePosition = useCallback(() => {
    if (!backdropPortal) return;

    const el = elementRef.current;
    const container = backdropPortal.containerRef.current;
    if (!el || !container) return;

    const elRect = el.getBoundingClientRect();
    const containerRect = container.getBoundingClientRect();

    // Calculate position relative to backdrop container
    const style: CSSProperties = {
      left: elRect.left - containerRect.left,
      top: elRect.top - containerRect.top,
      width: elRect.width,
      height: elRect.height,
      backdropFilter,
      WebkitBackdropFilter: backdropFilter,
      backgroundColor,
      borderRadius,
    };

    backdropPortal.updateBackdrop(id, style);
  }, [backdropPortal, id, backdropFilter, backgroundColor, borderRadius]);

  // Throttled position update using requestAnimationFrame
  const schedulePositionUpdate = useCallback(() => {
    if (rafIdRef.current !== null) return;
    rafIdRef.current = requestAnimationFrame(() => {
      rafIdRef.current = null;
      updatePosition();
    });
  }, [updatePosition]);

  useEffect(() => {
    if (!enabled || !backdropPortal) return;

    const el = elementRef.current;
    if (!el) return;

    // Register backdrop with initial empty style
    backdropPortal.registerBackdrop(id, {}, zIndex);

    // Initial position update
    updatePosition();

    // Update position on resize
    const resizeObserver = new ResizeObserver(() => {
      schedulePositionUpdate();
    });
    resizeObserver.observe(el);

    // Update position on window resize (viewport changes)
    const handleResize = () => schedulePositionUpdate();
    window.addEventListener('resize', handleResize);

    // Update position on scroll (in case of scrollable containers)
    const handleScroll = () => schedulePositionUpdate();
    window.addEventListener('scroll', handleScroll, true);

    // Use IntersectionObserver to detect when element position might change
    // This is more efficient than MutationObserver on document.body
    const intersectionObserver = new IntersectionObserver(
      () => {
        schedulePositionUpdate();
      },
      { threshold: [0, 0.5, 1] },
    );
    intersectionObserver.observe(el);

    return () => {
      backdropPortal.unregisterBackdrop(id);
      resizeObserver.disconnect();
      intersectionObserver.disconnect();
      window.removeEventListener('resize', handleResize);
      window.removeEventListener('scroll', handleScroll, true);
      if (rafIdRef.current !== null) {
        cancelAnimationFrame(rafIdRef.current);
      }
    };
  }, [
    enabled,
    backdropPortal,
    id,
    zIndex,
    updatePosition,
    schedulePositionUpdate,
  ]);

  // Update position when style properties change
  useEffect(() => {
    if (enabled && backdropPortal) {
      updatePosition();
    }
  }, [
    enabled,
    backdropPortal,
    backdropFilter,
    backgroundColor,
    borderRadius,
    updatePosition,
  ]);

  // Update position after every render to catch position changes during drag operations
  // useLayoutEffect runs synchronously after DOM mutations but before paint
  useLayoutEffect(() => {
    if (enabled && backdropPortal && elementRef.current) {
      updatePosition();
    }
  });

  return { ref: elementRef, isPortalAvailable };
}

export default useBackdropEffect;
