import Logger from 'src/application/logging/logger';
import {
  BaseEcommerceEvent,
  isBaseEcommerceEvent,
  isGA4EcommerceEvent,
  isLegacyUAEcommerceEvent,
} from 'src/application/models';
import { SpiffyMetricsEventName } from 'src/services/amplitudeService/amplitudeService';

declare global {
  interface Window {
    dataLayer: any[];
  }
}

const NORMALIZED_ADD_TO_CART_EVENT_NAMES = ['addtocart', 'addedtocart'];
const CHECK_DATA_LAYER_INTERVAL_MS = 500;
const CHECK_DATA_LAYER_MAX_ATTEMPTS = 10;

const logger = new Logger('analyticsUtils');

/**
 * Checks if a Google Analytics event is an add_to_cart event.
 *
 * @param event The event name to check.
 *
 * @returns True if the event is an add_to_cart event, false otherwise.
 */
const isAddToCartEvent = (event: string): boolean => {
  const normalizedEvent = event.replace(/[-_]/g, '').toLowerCase();
  return NORMALIZED_ADD_TO_CART_EVENT_NAMES.some(name => normalizedEvent.includes(name));
};

/**
 * Tracks an add_to_cart event in Amplitude.
 *
 * @param event The event to track.
 */
const handleAddToCartEvent = (
  event: BaseEcommerceEvent,
  track: (eventName: SpiffyMetricsEventName, eventProps?: Record<string, unknown>) => void,
) => {
  let eventProps: Record<string, unknown>;

  if (isLegacyUAEcommerceEvent(event)) {
    eventProps = {
      items: event.ecommerce.add.products.map(product => ({
        item_name: product.name,
        item_category: product.category,
        price: product.price,
        quantity: product.quantity,
      })),
      currency: event.ecommerce.add.currencyCode,
      event_format_version: 'legacy_universal_analytics',
    };
  } else if (isGA4EcommerceEvent(event)) {
    eventProps = {
      items: event.ecommerce.items.map(item => ({
        item_name: item.item_name,
        item_category: item.item_category,
        price: item.price,
        quantity: item.quantity,
      })),
      currency: event.ecommerce.currency,
      event_format_version: 'google_analytics_4',
    };
  } else {
    eventProps = {
      event_properties: { ...event },
      event_format_version: 'unknown',
    };
  }

  track(SpiffyMetricsEventName.AddToCartClicked, {
    eventProps,
  });
};

/**
 * Wraps the window.dataLayer.push method to intercept add_to_cart events and send them to Amplitude.
 * This function runs on an interval until the dataLayer is available.
 */
export const initDataLayerWrapper = (
  track: (eventName: SpiffyMetricsEventName, eventProps?: Record<string, unknown>) => void,
) => {
  let attempts = 0;

  // currently, our bundle is always loaded after GTM has initialized GA/dataLayer
  // we'll need this check here if/when we load spiffy before/outside of GTM
  const checkAndInitialize = () => {
    if (!window.dataLayer || !(window.dataLayer as any).push) {
      attempts += 1;

      if (attempts >= CHECK_DATA_LAYER_MAX_ATTEMPTS) {
        logger.logDebug(`dataLayer not available after ${CHECK_DATA_LAYER_MAX_ATTEMPTS} attempts`);
        return;
      }

      setTimeout(checkAndInitialize, CHECK_DATA_LAYER_INTERVAL_MS);
      return;
    }

    logger.logDebug('dataLayer is available, wrapping push function...');
    const originalPush = window.dataLayer.push;
    window.dataLayer.push = (...args: unknown[]) => {
      if (isBaseEcommerceEvent(args[0]) && isAddToCartEvent((args[0] as any).event)) {
        handleAddToCartEvent(args[0] as BaseEcommerceEvent, track);
      }

      // IMPORTANT: call the original push method so that the event is still logged to GA
      return originalPush.apply(window.dataLayer, args);
    };
  };

  checkAndInitialize();
};

export const initAmplitude = (
  track: (eventName: SpiffyMetricsEventName, eventProps?: Record<string, unknown>) => void,
) => {
  // This function might not be needed anymore if Amplitude is initialized via context.
  // For now, we'll keep it and pass the track function.
  // If it's truly redundant, it can be removed later.
  track(SpiffyMetricsEventName.BundleLoaded); // Example usage, adjust as needed
};
