(() => {
  const SPINNER_COLOR = '#E6682D';
  const SPINNER_BACKGROUND = '#FBF7EF';
  const SCRIPT_DEAD_TIMEOUT = 3000;
  const MAX_WAIT_AFTER_STARTED = 15000;
  const SPINNER_HIDE_DURATION = 600;
  const BODY_SHOW_DURATION = 600;
  const CLEANUP_DELAY = 600;
  const MODE = 'dev'; // prod | dev

  const hasStorageFlag = () => {
    try {
      return window.localStorage.getItem('recode_payment_page_dev') === 'true';
    } catch {
      return false;
    }
  };

  const hasQueryFlag = new URL(window.location.href).searchParams.has('recode_dev');
  const hasDevFlag = hasStorageFlag() || hasQueryFlag;
  const isCustomizationEnabled = MODE === 'prod' || hasDevFlag === true;
  const HTML_READY_CLASS = 'recode-document-ready';
  const HTML_ACTIVE_CLASS = 'recode-loader-active';

  const EVENTS = {
    STARTED: 'recodePaymentPageStarted',
    READY: 'recodePaymentPageReady',
  };

  const loaderState = {
    isRevealScheduled: false,
    hasStarted: false,
    deadTimeoutId: null,
    startedTimeoutId: null,
  };

  const checkPaymentPage = () => {
    const url = window.location.href;

    return url.includes('/sales/shop/dealPay/id/') && !url.includes('editMode=1');
  };

  const waitForBody = (handleReady) => {
    const readinessState = { isHandled: false };

    const resolveIfReady = () => {
      if (readinessState.isHandled) {
        return;
      }

      if (!document.body) {
        return;
      }

      readinessState.isHandled = true;
      handleReady(document.body);
    };

    if (document.body) {
      resolveIfReady();

      return;
    }

    const observer = new MutationObserver(() => {
      resolveIfReady();

      if (!readinessState.isHandled) {
        return;
      }

      observer.disconnect();
    });

    observer.observe(document.documentElement, { childList: true });

    document.addEventListener(
      'DOMContentLoaded',
      () => {
        observer.disconnect();
        resolveIfReady();
      },
      { once: true },
    );
  };

  const createStyles = () => {
    const styleElement = document.createElement('style');

    styleElement.innerHTML = `
      html.${HTML_ACTIVE_CLASS} {
        background: ${SPINNER_BACKGROUND};
      }

      html.${HTML_ACTIVE_CLASS} body {
        opacity: 0;
        transition: opacity ${BODY_SHOW_DURATION}ms ease-in-out;
      }

      html.${HTML_ACTIVE_CLASS}:before {
        content: "";
        position: fixed;
        top: 50%;
        left: 50%;
        display: block;
        width: 40px;
        height: 40px;
        border-top: 5px solid transparent;
        border-right: 5px solid transparent;
        border-bottom: 5px solid ${SPINNER_COLOR};
        border-left: 5px solid ${SPINNER_COLOR};
        transform: translateZ(0);
        border-radius: 100%;
        transition: opacity ${SPINNER_HIDE_DURATION}ms ease-in-out;
        animation: recode-loader 1.2s infinite cubic-bezier(0.4, 0, 0.2, 1);
        pointer-events: none;
        z-index: 9999;
      }

      html.${HTML_ACTIVE_CLASS}.${HTML_READY_CLASS}:before {
        opacity: 0;
      }

      @keyframes recode-loader {
        0% {
          transform: translate(-50%, -50%) rotate(0deg);
        }
        100% {
          transform: translate(-50%, -50%) rotate(360deg);
        }
      }
    `;

    return styleElement;
  };

  const clearDeadTimeout = () => {
    if (!loaderState.deadTimeoutId) {
      return;
    }

    clearTimeout(loaderState.deadTimeoutId);
    loaderState.deadTimeoutId = null;
  };

  const clearStartedTimeout = () => {
    if (!loaderState.startedTimeoutId) {
      return;
    }

    clearTimeout(loaderState.startedTimeoutId);
    loaderState.startedTimeoutId = null;
  };

  const cleanupLoader = (styles) => {
    styles.remove();
    document.documentElement.classList.remove(HTML_READY_CLASS);
    document.documentElement.classList.remove(HTML_ACTIVE_CLASS);
    document.body.style.opacity = '';
  };

  const showBody = (styles) => {
    document.body.style.opacity = '1';

    setTimeout(() => cleanupLoader(styles), CLEANUP_DELAY);
  };

  const revealBody = (styles) => {
    if (!styles.parentNode) {
      return;
    }

    document.documentElement.classList.add(HTML_READY_CLASS);

    setTimeout(() => showBody(styles), SPINNER_HIDE_DURATION);
  };

  const showContent = (styles) => {
    if (loaderState.isRevealScheduled) {
      return;
    }

    loaderState.isRevealScheduled = true;

    clearDeadTimeout();
    clearStartedTimeout();

    waitForBody(() => revealBody(styles));
  };

  const handleStarted = (styles) => {
    if (loaderState.hasStarted) {
      return;
    }

    loaderState.hasStarted = true;

    clearDeadTimeout();

    loaderState.startedTimeoutId = setTimeout(() => {
      showContent(styles);
    }, MAX_WAIT_AFTER_STARTED);
  };

  const scheduleDeadReveal = (styles) => {
    loaderState.deadTimeoutId = setTimeout(() => {
      showContent(styles);
    }, SCRIPT_DEAD_TIMEOUT);
  };

  const initLoader = () => {
    if (!checkPaymentPage()) {
      return;
    }

    if (!isCustomizationEnabled) {
      return;
    }

    if (document.documentElement.classList.contains(HTML_ACTIVE_CLASS)) {
      return;
    }

    const styles = createStyles();

    document.head.appendChild(styles);
    document.documentElement.classList.add(HTML_ACTIVE_CLASS);

    scheduleDeadReveal(styles);

    document.addEventListener(
      EVENTS.STARTED,
      () => {
        handleStarted(styles);
      },
      { once: true },
    );

    document.addEventListener(
      EVENTS.READY,
      () => {
        clearDeadTimeout();
        clearStartedTimeout();
        showContent(styles);
      },
      { once: true },
    );
  };

  initLoader();
})();