import React, {
  createContext,
  ReactNode,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
} from 'react';
import {
  ANALYTICS_CONSENT_CHANGED_EVENT,
  AnalyticsConsentStatus,
  getAnalyticsConsent,
  isAnalyticsEnvironment,
  setAnalyticsConsent,
} from '../utils/analyticsConsent';
import { flushAnalyticsQueue } from '../utils/analytics';

type AnalyticsConsentContextValue = {
  consent: AnalyticsConsentStatus;
  hasConsent: boolean;
  isResolved: boolean;
  showBanner: boolean;
  acceptAnalytics: () => void;
  declineAnalytics: () => void;
};

const AnalyticsConsentContext = createContext<AnalyticsConsentContextValue | undefined>(
  undefined,
);

type AnalyticsConsentProviderProps = {
  children?: ReactNode;
};

export const AnalyticsConsentProvider = ({ children }: AnalyticsConsentProviderProps) => {
  const [consent, setConsent] = useState<AnalyticsConsentStatus>(() => getAnalyticsConsent());

  useEffect(() => {
    const onConsentChanged = (event: Event) => {
      const next = (event as CustomEvent<AnalyticsConsentStatus>).detail;
      if (next === 'granted' || next === 'denied') {
        setConsent(next);
      } else {
        setConsent(getAnalyticsConsent());
      }
    };

    window.addEventListener(ANALYTICS_CONSENT_CHANGED_EVENT, onConsentChanged);
    return () => window.removeEventListener(ANALYTICS_CONSENT_CHANGED_EVENT, onConsentChanged);
  }, []);

  const acceptAnalytics = useCallback(() => {
    setAnalyticsConsent('granted');
    setConsent('granted');
    flushAnalyticsQueue();
  }, []);

  const declineAnalytics = useCallback(() => {
    setAnalyticsConsent('denied');
    setConsent('denied');
  }, []);

  const value = useMemo<AnalyticsConsentContextValue>(
    () => ({
      consent,
      hasConsent: consent === 'granted',
      isResolved: consent !== 'pending',
      showBanner: isAnalyticsEnvironment() && consent === 'pending',
      acceptAnalytics,
      declineAnalytics,
    }),
    [acceptAnalytics, consent, declineAnalytics],
  );

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

export const useAnalyticsConsent = (): AnalyticsConsentContextValue => {
  const context = useContext(AnalyticsConsentContext);
  if (!context) {
    throw new Error('useAnalyticsConsent must be used within AnalyticsConsentProvider');
  }
  return context;
};
