import {
  ReactNode,
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';
import {
  UrlResolverResponse,
  hasParsedVariantInfoAtom,
  pageUserEventAtom,
  pageVariantInfoAtom,
  urlResolverAtom,
  variantInfoAtom,
} from 'src/atoms/app/variant';
import { useAtom, useAtomValue } from 'jotai';
import CommerceApiClient from 'src/application/commerce-api';
import Logger from 'src/application/logging/logger';
import { PageVisitCategory, UserEventCategory } from '@spiffy-ai/commerce-api-client';
import { VariantTypeEnum } from 'src/application/models';
import { EnviveMetricsEventName, useAmplitude } from 'src/contexts/amplitudeContext';
import { mapApiUserEventToUserEvent, mapUrlResolverResponseToVariantInfo } from './mapping';
import { PageDetails } from './types';

const logger = new Logger('pageContext');

const PageContext = createContext<
  | (PageDetails & {
      isLoading: boolean;
      isSupported: boolean;
      setPageUrl: (url: string) => void;
    })
  | undefined
>(undefined);

export const PageProvider: React.FC<{
  children: ReactNode;
  previewMode: boolean;
  /** When URL resolver returns `ready: false`, invoked for extension/injection failure reporting. */
  onUrlResolverNotReady?: (error: Error) => Promise<unknown> | void;
}> = ({ children, previewMode = false, onUrlResolverNotReady }) => {
  const [pageUrl, setPageUrl] = useState<string | undefined>(undefined);
  const [urlResolverResponse, setUrlResolverResponse] = useAtom(urlResolverAtom);
  const [isLoading, setIsLoading] = useState(false);
  const [variantInfo, setVariantInfo] = useAtom(pageVariantInfoAtom);
  const [userEvent, setUserEvent] = useAtom(pageUserEventAtom);
  const [isSupported, setIsSupported] = useState(false);
  const lastNotReadyUrlRef = useRef<string | null>(null);

  useEffect(() => {
    setPageUrl(window.location.href);
  }, []);

  // Auto-initialize atoms for preview mode
  useEffect(() => {
    if (previewMode && !userEvent && !variantInfo) {
      const url = typeof window !== 'undefined' ? window.location.href : '';
      setUserEvent({
        event_id: 'preview-user-event',
        created_at: new Date().toISOString(),
        category: UserEventCategory.PageVisit,
        attributes: {
          page_visit_category: PageVisitCategory.Other,
          url,
        },
      } as any);

      setVariantInfo({
        variantType: VariantTypeEnum.PageVisit,
        url,
      });
    }
  }, [previewMode, userEvent, variantInfo, setUserEvent, setVariantInfo]);

  const setVariantFromUrlResolver = useCallback(
    (url: string, response: UrlResolverResponse) => {
      if (response.ready) {
        const newVariantInfo = mapUrlResolverResponseToVariantInfo(url, response);
        const newUserEvent = mapApiUserEventToUserEvent(response.user_event ?? undefined);
        logger.logDebug('setting variant info and user event', { newVariantInfo, newUserEvent });
        setVariantInfo(newVariantInfo);
        setUserEvent(newUserEvent);
      } else {
        setUserEvent(undefined);
        setVariantInfo(undefined);
        logger.logDebug('set variant info and user event to undefined', { variantInfo, userEvent });
      }
    },
    [setVariantInfo, setUserEvent],
  );

  useEffect(() => {
    const resolvePageUrl = async () => {
      setIsLoading(true);
      try {
        if (!pageUrl) {
          setIsLoading(false);
          return;
        }

        // If in preview mode or atoms are already set (e.g., by storybook), skip API call
        if (previewMode || userEvent || variantInfo) {
          setIsLoading(false);
          return;
        }

        const cleansedUrl = pageUrl.toLowerCase().trim();
        const response =
          urlResolverResponse[cleansedUrl] ??
          ((await CommerceApiClient.resolveUrl(cleansedUrl)) as UrlResolverResponse);
        setVariantFromUrlResolver(cleansedUrl, response);
        setIsLoading(false);
        setIsSupported(response.ready);

        if (response.ready) {
          lastNotReadyUrlRef.current = null;
        } else if (onUrlResolverNotReady && lastNotReadyUrlRef.current !== cleansedUrl) {
          lastNotReadyUrlRef.current = cleansedUrl;
          const err = new Error(`URL resolver returned ready=false for ${cleansedUrl}`);
          Promise.resolve(onUrlResolverNotReady(err)).catch(callbackError => {
            logger.logDebug('onUrlResolverNotReady callback failed', callbackError);
          });
        }
      } catch (e) {
        setIsLoading(false);
        logger.logError('Failed to resolve page URL', e, { pageUrl });
      }
    };
    resolvePageUrl();
  }, [
    pageUrl,
    urlResolverResponse,
    setUrlResolverResponse,
    setVariantFromUrlResolver,
    userEvent,
    variantInfo,
    previewMode,
    onUrlResolverNotReady,
  ]);

  const { trackEvent } = useAmplitude();
  const resolvedVariantInfo = useAtomValue(variantInfoAtom);
  const hasParsedVariantInfo = useAtomValue(hasParsedVariantInfoAtom);
  const pageViewedFired = useRef(false);

  useEffect(() => {
    if (pageViewedFired.current || isLoading || !hasParsedVariantInfo || !variantInfo) {
      return;
    }

    let pageType: string;
    let pageId: string;

    switch (variantInfo.variantType) {
      case VariantTypeEnum.Pdp:
        pageType = 'pdp';
        pageId = variantInfo.productId;
        break;
      case VariantTypeEnum.Plp:
        pageType = 'plp';
        pageId = variantInfo.plpId;
        break;
      case VariantTypeEnum.Home:
        pageType = 'homepage';
        pageId = variantInfo.url;
        break;
      case VariantTypeEnum.Other:
        pageType = 'other';
        pageId = variantInfo.url;
        break;
      case VariantTypeEnum.PageVisit:
        pageType = 'other';
        pageId = variantInfo.url;
        break;
      case VariantTypeEnum.FullPageSalesAgent:
        pageType = 'full_page_sales_agent';
        pageId = variantInfo.url;
        break;
      default:
        return;
    }

    pageViewedFired.current = true;

    trackEvent({
      eventName: EnviveMetricsEventName.PageViewed,
      eventProps: {
        'context.page_type': pageType,
        'context.page_id': pageId,
        'context.supported': isSupported,
        'context.ready': isSupported,
        'context.page_variant_id': resolvedVariantInfo.variantId,
      },
    });
  }, [isLoading, isSupported, hasParsedVariantInfo, variantInfo, resolvedVariantInfo, trackEvent]);

  const setPageUrlStable = useCallback((url: string) => {
    setPageUrl(url);
  }, []);

  const value = useMemo(
    () => ({
      pageUrl,
      variantInfo,
      userEvent,
      isLoading,
      isSupported,
      setPageUrl: setPageUrlStable,
    }),
    [pageUrl, userEvent, variantInfo, isLoading, isSupported, setPageUrlStable],
  );

  return <PageContext.Provider value={value}>{children}</PageContext.Provider>;
};

export const usePage = () => {
  const context = useContext(PageContext);
  if (!context) {
    throw new Error('usePage must be used within a PageProvider');
  }
  return context;
};
