import { RefObject, useEffect, useRef } from 'react';
import { useStore } from '../services/store';

/** Duration the widget must be continuously visible before the timer condition is met. */
const ENGAGED_DURATION_MS = 1000;

/**
 * Module-level guard: prevents widgetObserved from firing more than once per
 * widget instance, even when React StrictMode double-mounts in development.
 */
const engagedViewFired = new Set<string>();

/**
 * Fires a single `widgetObserved` event when the widget has been ENTIRELY
 * visible in the viewport for at least 1 second continuously.
 *
 * The timer resets whenever any part of the widget leaves the viewport.
 *
 * @param widgetRef - Ref attached to the widget root element.
 */
export default function useWidgetObserved(widgetRef: RefObject<Element | null>): void {
  const store = useStore();
  const { data, triggerEvent } = store;
  const widgetId = data?.id;
  const layout = data?.settings?.type;

  const timerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);
  const firedRef = useRef(false);

  useEffect(() => {
    const el = widgetRef.current;
    if (!widgetId || !el) return () => {};

    // Skip setup if the event has already fired for this widget instance.
    if (engagedViewFired.has(widgetId)) {
      firedRef.current = true;
      return () => {};
    }

    // ── Full-visibility timer ──────────────────────────────────────────────────
    // The timer starts only when the entire widget is visible (threshold: 1.0).
    // If any part of it leaves the viewport before the second elapses, the
    // timer is cancelled and will only restart on the next full-visibility entry.
    const observer = new IntersectionObserver(
      (entries) => {
        const [entry] = entries;
        if (!entry) return;

        if (entry.isIntersecting && !timerRef.current && !firedRef.current) {
          timerRef.current = setTimeout(() => {
            timerRef.current = undefined;
            if (!firedRef.current) {
              engagedViewFired.add(widgetId);
              firedRef.current = true;
              triggerEvent('widgetObserved', { layout }, widgetId);
            }
          }, ENGAGED_DURATION_MS);
        } else if (!entry.isIntersecting && timerRef.current) {
          clearTimeout(timerRef.current);
          timerRef.current = undefined;
        }
      },
      { threshold: 1.0 },
    );
    observer.observe(el);

    return () => {
      observer.disconnect();
      if (timerRef.current) {
        clearTimeout(timerRef.current);
        timerRef.current = undefined;
      }
    };
  }, [widgetId, layout, widgetRef, triggerEvent]);
}
