type RevealOptions = {
  delay?: number;
  distance?: number;
  threshold?: number;
};

const defaultOptions: Required<RevealOptions> = {
  delay: 0,
  distance: 24,
  threshold: 0.18
};

export function reveal(node: HTMLElement, options: RevealOptions = {}) {
  const settings = { ...defaultOptions, ...options };
  const media = window.matchMedia('(prefers-reduced-motion: reduce)');

  if (media.matches) {
    node.classList.add('reveal-visible');
    return {
      destroy() {}
    };
  }

  node.style.setProperty('--reveal-delay', `${settings.delay}ms`);
  node.style.setProperty('--reveal-distance', `${settings.distance}px`);
  node.classList.add('reveal-ready');

  // If the element is already visible at all in the initial viewport,
  // reveal it immediately so the first section below the hero doesn't
  // appear blank on page load.
  const initialCheck = () => {
    const rect = node.getBoundingClientRect();
    const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
    if (rect.top < viewportHeight && rect.bottom > 0) {
      node.classList.add('reveal-visible');
      return true;
    }
    return false;
  };

  if (initialCheck()) {
    return {
      destroy() {}
    };
  }

  const observer = new IntersectionObserver(
    (entries) => {
      for (const entry of entries) {
        if (entry.isIntersecting) {
          node.classList.add('reveal-visible');
          continue;
        }

        const viewportHeight = window.innerHeight || document.documentElement.clientHeight;
        const rect = entry.boundingClientRect;
        const fullyOutOfView = rect.bottom <= 0 || rect.top >= viewportHeight;

        if (fullyOutOfView) {
          node.classList.remove('reveal-visible');
        }
      }
    },
    {
      threshold: settings.threshold,
      rootMargin: '0px 0px -8% 0px'
    }
  );

  observer.observe(node);

  return {
    destroy() {
      observer.disconnect();
    }
  };
}
