import { useEffect } from 'react';
import { widgetStore } from '../store';
import { WidgetUIPhase } from '../types';
import { useSelectedFieldStore } from './useSelectedFieldStore';
import { useWidgetActions } from './useWidgetActions';
import { useWidgetUIPhase } from './useWidgetUIPhase';

export type UseWidgetExpiryEffectArg = {
  widgetId: string;
};

const MAX_SET_TIMEOUT_DELAY = 2147483647;

/**
 * @description useWidgetExpiryEffect hook runs a timer to update widget UI phase to EXPIRED
 * once the expiry time has passed. Expiry time is set when creating widget from producer suite
 * @since 0.1.0
 */
export function useWidgetExpiryEffect({ widgetId }: UseWidgetExpiryEffectArg) {
  const { updateWidgetUIPhaseAction } = useWidgetActions({ widgetId });
  const expiredTimeStamp = useSelectedFieldStore(
    widgetStore,
    () => widgetStore.get()[widgetId]?.widgetPayload?.interactive_until
  );
  const currentWidgetUIPhase = useWidgetUIPhase({ widgetId });
  const isWidgetEndUIPhase =
    currentWidgetUIPhase === WidgetUIPhase.INTERACTIVE_TIMED_OUT ||
    currentWidgetUIPhase === WidgetUIPhase.FOLLOW_UP_PUBLISHED;

  useEffect(() => {
    if (!expiredTimeStamp || isWidgetEndUIPhase) return;
    const expiredTime = new Date(expiredTimeStamp);
    let expiryTimeout;
    function expiryTimeoutFn() {
      const timeout = expiredTime.getTime() - Date.now();
      if (timeout <= 0) {
        updateWidgetUIPhaseAction({
          widgetId,
          widgetUIPhase: WidgetUIPhase.EXPIRED,
        });
        return;
      }

      // setTimeout stores the delay as 32-bit signed integer. So, when interactive_until is set
      // for more than 24.8 days later, the code executes immediately disabling the widget.
      // The below if condition is added to handle the same.
      // If timeout is greater than MAX_SET_TIMEOUT_DELAY, a setTimeout with MAX_SET_TIMEOUT_DELAY
      // as the delay will run which will recursively call startInteractiveUntilTimer again and
      // again until the timeout is less than MAX_SET_TIMEOUT_DELAY and eventually sets this.disabled as true
      if (timeout > MAX_SET_TIMEOUT_DELAY) {
        expiryTimeout = setTimeout(() => {
          expiryTimeoutFn();
        }, MAX_SET_TIMEOUT_DELAY);
      } else {
        expiryTimeout = setTimeout(() => {
          updateWidgetUIPhaseAction({
            widgetId,
            widgetUIPhase: WidgetUIPhase.EXPIRED,
          });
        }, timeout);
      }
    }
    expiryTimeoutFn();

    return () => {
      clearTimeout(expiryTimeout);
    };
  }, [expiredTimeStamp, isWidgetEndUIPhase]);
}
