import { v4 as uuidv4 } from 'uuid';

import {
  ContextualProperties,
  FeatureSessionType,
} from '@/logging/BaseWebUserEventProperties';
import { getAnonymousId, track as segmentTrack } from '@/logging/segmentClient';
import { SessionStore } from '@/state/sessionStore';
import { getPWADisplayMode } from '@/utils/pwaDisplayMode';

import { isDev } from '../utils/environment';
import {
  HookGeneralEvent,
  HookPlaybackEvent,
  TrackingEvent,
  WebUserEvent,
} from './TrackingEventTypes';
import { extendAnalyticsSessionId } from './analyticsSessions';
import { eventSubscribers } from './eventSubscribers';
import HookGeneralEventType from './eventTypes/HookGeneralEventType';
import HookPlaybackEventType from './eventTypes/HookPlaybackEventType';

export const getShouldStringifyPayloads = () => {
  return (
    typeof localStorage !== 'undefined' &&
    localStorage.getItem('stringifyTrackingPayloads-dec-5-2024') === 'true'
  );
};

export const getShouldLogEventsToConsole = () => {
  return (
    isDev ||
    (typeof localStorage !== 'undefined' &&
      localStorage.getItem('logEventsToConsole-dec-28-2024') === 'true')
  );
};

export const logToConsole = (name: string, properties: Record<string, any>) => {
  console.log(
    `Would Track`,
    name,
    getShouldStringifyPayloads()
      ? JSON.stringify(properties, null, 2)
      : properties
  );
};

const log = (name: string, properties: Record<string, any>) => {
  if (getShouldLogEventsToConsole()) {
    logToConsole(name, properties);
  }

  segmentTrack(name, properties);
};

const contextualProperties: ContextualProperties = {
  userId: null,
  featureSessionId: null,
  featureSessionType: null,
};

const logEvent = (
  {
    // Please do not change the default event name, all the web events should use the same event name. Please use actionName in properties to differentiate the event type.
    // The format of actionName is <ProductName><ActionName/ImpressionName><Type>
    eventName,
    properties,
  }: TrackingEvent | HookPlaybackEvent | HookGeneralEvent,
  session?: SessionStore
) => {
  // important - don't do this in the `await` below or contextual properties might have changed.
  const extendedProperties: Record<string, any> = {
    ...properties,
    ...contextualProperties,
  };

  (async () => {
    const seed = {
      deviceId: await getAnonymousId(),
    };

    extendAnalyticsSessionId(
      contextualProperties.userId,
      JSON.stringify(seed),
      Date.now() / 1000
    )
      .then((sessionId) => {
        if (sessionId && properties) {
          extendedProperties.sessionId = sessionId;
        }
        log(eventName, extendedProperties);
        if (session?.flags?.['event-subscribers']) {
          Promise.all(
            eventSubscribers?.map((subscriber) =>
              subscriber.push(eventName, extendedProperties)
            ) || []
          );
        }
      })
      .catch((error: any) => {
        console.error('Error Extending Analytics Session ID', error);
        log(eventName, extendedProperties);
      });
  })();
};

export default function logWebUserEvent(
  properties: WebUserEvent & { transactionUuid?: string },
  session?: SessionStore
) {
  logEvent(
    {
      eventName: 'Web-User-Event',
      properties: {
        ...properties,
        displayMode: getPWADisplayMode(),
      } as WebUserEvent & { displayMode: string },
    },
    session
  );
}

export type TransactionLogger = {
  logWebUserEvent: (properties: WebUserEvent) => void;
  transactionUuid: string;
};

export const createTransactionLogger = (): TransactionLogger => {
  const transactionUuid = uuidv4();
  return {
    logWebUserEvent: (properties: WebUserEvent) => {
      logWebUserEvent({
        ...properties,
        transactionUuid,
      } as WebUserEvent & { transactionUuid: string });
    },
    transactionUuid,
  };
};

export const identifyUser = (userId: string) => {
  contextualProperties.userId = userId;
  logWebUserEvent({
    actionName: 'Identify',
    // userId assigned automatically.
  });
};

export const logoutUser = () => {
  contextualProperties.userId = null;
  // TODO: should we have segment rotate anonymousId here?
};

export const assignFeatureSession = (
  featureSessionType: FeatureSessionType | null,
  featureSessionId: string | null
) => {
  contextualProperties.featureSessionType = featureSessionType;
  contextualProperties.featureSessionId = featureSessionId;
};

export const logHookWebPlaybackEvent = (properties: HookPlaybackEventType) => {
  logEvent({
    eventName: 'Hook-Web-Event',
    properties,
  });
};

export const logHookWebGeneralEvent = (properties: HookGeneralEventType) => {
  logEvent({
    eventName: 'Hook-Web-Event',
    properties,
  });
};

export const withWebUserEvent = <T>(
  getEvent:
    | (() => WebUserEvent & { transactionUuid?: string })
    | (WebUserEvent & { transactionUuid?: string }),
  clickHandler: (e: React.MouseEvent<HTMLElement>) => T
) => {
  return (e: React.MouseEvent<HTMLElement>) => {
    logWebUserEvent(typeof getEvent === 'function' ? getEvent() : getEvent);
    return clickHandler(e);
  };
};
