import { useCallback, useRef } from 'react';
import { IWidgetOptionItem, hasDebugLogger } from '@livelike/javascript';
import { useWidgetActions } from './useWidgetActions';
import { useWidgetInteractionActions } from './useWidgetInteractionActions';
import { useWidgetInteractions } from './useWidgetInteractions';
import { useWidgetOptions } from './useWidgetOptions';
import { useWidgetInteractedAnalytics } from './useWidgetInteractedAnalytics';

export type UseCheerMeterOnOptionPressArg = {
  widgetId: string;
  optionIndex: number;
  throttleTime: number;
};

export const useCheerMeterOnOptionPress = ({
  widgetId,
  optionIndex,
  throttleTime,
}: UseCheerMeterOnOptionPressArg) => {
  const throttleRef = useRef({
    prevDateTime: undefined,
    timeout: undefined,
    cacheVoteCount: 0,
  });
  const widgetOptions = useWidgetOptions({ widgetId });

  const { createWidgetInteractionAction, updateWidgetInteractionAction } =
    useWidgetInteractionActions({ widgetId });
  const { updateWidgetOptionsAction } = useWidgetActions({ widgetId });
  const widgetOption = widgetOptions?.[optionIndex];
  const widgetInteractions = useWidgetInteractions({ widgetId });
  const { trackWidgetInteractedAction } = useWidgetInteractedAnalytics({
    widgetId,
  });
  const hasInteractedOption = !!widgetInteractions?.find(
    ({ option_id }) => option_id === widgetOption?.id
  );

  return useCallback(() => {
    let { timeout, prevDateTime, cacheVoteCount } = throttleRef.current;

    const now = Date.now();
    clearTimeout(timeout);
    throttleRef.current.cacheVoteCount = cacheVoteCount + 1;
    if (!prevDateTime || now - prevDateTime >= throttleTime) {
      updateCount();
      prevDateTime = now;
    } else {
      timeout = setTimeout(
        () => updateCount(),
        throttleTime - (now - prevDateTime)
      );
    }
    throttleRef.current = {
      prevDateTime,
      timeout,
      cacheVoteCount: throttleRef.current.cacheVoteCount,
    };
    function updateCount() {
      const interactionItem = {
        ...widgetOptions[optionIndex],
        vote_count: throttleRef.current.cacheVoteCount,
      };
      trackWidgetInteractedAction<IWidgetOptionItem>({
        interactionItem: widgetOptions[optionIndex],
      });
      throttleRef.current = {
        ...throttleRef.current,
        // reset cache vote count
        cacheVoteCount: 0,
      };

      (hasInteractedOption
        ? updateWidgetInteractionAction({ interactionItem })
        : createWidgetInteractionAction({ interactionItem })
      )
        .then((res) => {
          if (!res) {
            return;
          }
          const updatedOptions = widgetOptions.map((option) => ({ ...option }));
          updatedOptions[optionIndex] = {
            ...updatedOptions[optionIndex],
            vote_count:
              updatedOptions[optionIndex].vote_count +
              interactionItem.vote_count,
          };
          updateWidgetOptionsAction({
            widgetId,
            widgetOptions: updatedOptions,
          });
        })
        .catch((e) => {
          hasDebugLogger() &&
            console.error(
              `Error while ${
                hasInteractedOption ? 'updating' : 'creating'
              } interaction`,
              e
            );
          // add earlier cache vote count back
          throttleRef.current = {
            ...throttleRef.current,
            // reset cache vote count
            cacheVoteCount: interactionItem.vote_count,
          };
        });
    }
  }, [
    throttleRef.current,
    optionIndex,
    hasInteractedOption,
    widgetOptions,
    updateWidgetInteractionAction,
    createWidgetInteractionAction,
  ]);
};
