import React, { createContext, useContext, useEffect, useMemo, useRef } from 'react';

import { AnalyticsClient } from './analytics-client';

import type { AnalyticsConfig, AnalyticsContext, ScrollDepth } from './types';

const AnalyticsContextInstance = createContext<AnalyticsContext | null>(null);

interface AnalyticsProviderProps {
  config: AnalyticsConfig;
  children: React.ReactNode;
}

export const AnalyticsProvider: React.FC<AnalyticsProviderProps> = ({
  config,
  children,
}) => {
  const client = useMemo(() => new AnalyticsClient(config), [config]);

  useEffect(() => {
    return () => {
      client.destroy();
    };
  }, [client]);

  const contextValue: AnalyticsContext = useMemo(
    () => ({
      trackView: client.trackView.bind(client),
      trackEngagement: client.trackEngagement.bind(client),
      trackInteraction: client.trackInteraction.bind(client),
      flush: client.flush.bind(client),
    }),
    [client],
  );

  // Automatic scroll tracking
  const scrollStateRef = useRef<{
    reached: Set<ScrollDepth>;
    pageLoadTime: number;
  }>({ reached: new Set(), pageLoadTime: Date.now() });

  useEffect(() => {
    if (!config.scrollTracking?.enabled || typeof window === 'undefined') {
      return;
    }

    const thresholds = config.scrollTracking.thresholds ?? [25, 50, 75, 100];
    const debounceMs = config.scrollTracking.debounceMs ?? 150;

    // Reset state on mount (handles route changes)
    scrollStateRef.current = { reached: new Set(), pageLoadTime: Date.now() };

    let timeoutId: ReturnType<typeof setTimeout> | null = null;

    const calculateScrollDepth = (): number => {
      const scrollTop = window.scrollY || document.documentElement.scrollTop;
      const viewportHeight = window.innerHeight;
      const documentHeight = document.documentElement.scrollHeight;
      const scrollableHeight = documentHeight - viewportHeight;

      if (scrollableHeight <= 0) return 100;
      return Math.min(100, Math.round((scrollTop / scrollableHeight) * 100));
    };

    const handleScroll = () => {
      if (timeoutId) clearTimeout(timeoutId);

      timeoutId = setTimeout(() => {
        const currentDepth = calculateScrollDepth();
        const foldPosition = window.innerHeight;
        const isBeyondFold = window.scrollY > foldPosition;
        const { reached, pageLoadTime } = scrollStateRef.current;

        for (const threshold of thresholds) {
          if (currentDepth >= threshold && !reached.has(threshold)) {
            reached.add(threshold);
            client.trackInteraction({
              type: 'scroll',
              data: {
                pageUrl: window.location.href,
                depth: threshold,
                timeToReachMs: Date.now() - pageLoadTime,
                isBeyondFold,
              },
            });
          }
        }
      }, debounceMs);
    };

    window.addEventListener('scroll', handleScroll, { passive: true });
    handleScroll(); // Check initial scroll position

    return () => {
      window.removeEventListener('scroll', handleScroll);
      if (timeoutId) clearTimeout(timeoutId);
    };
  }, [client, config.scrollTracking]);

  return (
    <AnalyticsContextInstance.Provider value={contextValue}>
      {children}
    </AnalyticsContextInstance.Provider>
  );
};

export const useAnalytics = (): AnalyticsContext => {
  const context = useContext(AnalyticsContextInstance);
  if (!context) {
    throw new Error('useAnalytics must be used within an AnalyticsProvider');
  }
  return context;
};
