(() => {
  const CONFIG = {
    SPINNER_COLOR: '#76B407',
    MAX_WAIT_TIME: 3000,
    MAX_WAIT_AFTER_INIT: 10000,
    DELAY_AFTER_READY: 500,
    SPINNER_HIDE_DURATION: 600,
    BODY_SHOW_DURATION: 600,
    CLEANUP_DELAY: 600,
  };

  const {
    SPINNER_COLOR,
    MAX_WAIT_TIME,
    MAX_WAIT_AFTER_INIT,
    DELAY_AFTER_READY,
    SPINNER_HIDE_DURATION,
    BODY_SHOW_DURATION,
    CLEANUP_DELAY,
  } = CONFIG;

  const HTML_READY_CLASS = 'recode-document-ready';
  const HTML_ACTIVE_CLASS = 'recode-loader-active';

  const EVENTS = {
    INIT: 'recodePaymentPageInit',
    READY: 'recodePaymentPageReady',
  };

  const loaderState = {
    isRevealScheduled: false,
    hasInitStarted: false,
    fallbackTimeoutId: null,
    initTimeoutId: 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 = (color) => {
    const styleElement = document.createElement('style');

    styleElement.innerHTML = `
      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 ${color};
        border-left: 5px solid ${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 clearFallbackTimeout = () => {
    if (!loaderState.fallbackTimeoutId) {
      return;
    }

    clearTimeout(loaderState.fallbackTimeoutId);
    loaderState.fallbackTimeoutId = null;
  };

  const clearInitTimeout = () => {
    if (!loaderState.initTimeoutId) {
      return;
    }

    clearTimeout(loaderState.initTimeoutId);
    loaderState.initTimeoutId = null;
  };

  const scheduleFallbackReveal = (styles) => {
    loaderState.fallbackTimeoutId = setTimeout(() => {
      showContent(styles);
    }, MAX_WAIT_TIME);
  };

  const handleInitStarted = (styles) => {
    if (loaderState.hasInitStarted) {
      return;
    }

    loaderState.hasInitStarted = true;

    clearFallbackTimeout();

    loaderState.initTimeoutId = setTimeout(() => {
      showContent(styles);
    }, MAX_WAIT_AFTER_INIT);
  };

  const showContent = (styles) => {
    if (loaderState.isRevealScheduled) {
      return;
    }

    loaderState.isRevealScheduled = true;

    clearFallbackTimeout();
    clearInitTimeout();

    waitForBody(() => {
      if (!styles.parentNode) {
        return;
      }

      document.documentElement.classList.add(HTML_READY_CLASS);

      setTimeout(() => {
        document.body.style.opacity = '1';

        setTimeout(() => {
          styles.remove();
          document.documentElement.classList.remove(HTML_READY_CLASS);
          document.documentElement.classList.remove(HTML_ACTIVE_CLASS);
        }, CLEANUP_DELAY);
      }, SPINNER_HIDE_DURATION);
    });
  };

  const initLoader = () => {
    if (!checkPaymentPage()) {
      return;
    }

    if (document.documentElement.classList.contains(HTML_ACTIVE_CLASS)) {
      return;
    }

    const styles = createStyles(SPINNER_COLOR);
    document.head.appendChild(styles);
    document.documentElement.classList.add(HTML_ACTIVE_CLASS);

    scheduleFallbackReveal(styles);

    document.addEventListener(
      EVENTS.INIT,
      () => {
        handleInitStarted(styles);
      },
      { once: true }
    );

    document.addEventListener(
      EVENTS.READY,
      () => {
        clearFallbackTimeout();
        clearInitTimeout();

        setTimeout(() => {
          showContent(styles);
        }, DELAY_AFTER_READY);
      },
      { once: true }
    );
  };

  initLoader();
})();