text: import { later } from "@ember/runloop";
  import {
    localCache,
    failedCache,
    setLocalCache,
    setFailedCache,
    resetLocalCache,
    resetFailedCache,
    normalize
  } from "pretty-text/oneboxer-cache";
  
  let timeout;
  const loadingQueue = [];
  
  export const LOADING_ONEBOX_CSS_CLASS = "loading-onebox";
  
  export function resetCache() {
    loadingQueue.clear();
    resetLocalCache();
    resetFailedCache();
  }
  
  function resolveSize(img) {
    $(img).addClass("size-resolved");
  
    if (img.width > 0 && img.width === img.height) {
      $(img).addClass("onebox-avatar");
    }
  }
  
  // Detect square images and apply smaller onebox-avatar class
  function applySquareGenericOnebox($elem, normalizedUrl) {
    if (!$elem.hasClass("whitelistedgeneric")) {
      return;
    }
  
    let $img = $elem.find(".onebox-body img.thumbnail");
    let img = $img[0];
  
    // already resolved... skip
    if ($img.length !== 1 || $img.hasClass("size-resolved")) {
      return;
    }
  
    if (img.complete) {
      resolveSize(img, $elem, normalizedUrl);
    } else {
      $img.on("load.onebox", () => {
        resolveSize(img, $elem, normalizedUrl);
        $img.off("load.onebox");
      });
    }
  }
  
  function loadNext(ajax) {
    if (loadingQueue.length === 0) {
      timeout = null;
      return;
    }
  
    let timeoutMs = 150;
    let removeLoading = true;
    const { url, refresh, $elem, categoryId, topicId } = loadingQueue.shift();
  
    // Retrieve the onebox
    return ajax("/onebox", {
      dataType: "html",
      data: {
        url,
        refresh,
        category_id: categoryId,
        topic_id: topicId
      },
      cache: true
    })
      .then(
        html => {
          let $html = $(html);
          setLocalCache(normalize(url), $html);
          $elem.replaceWith($html);
          applySquareGenericOnebox($html, normalize(url));
        },
        result => {
          if (result && result.jqXHR && result.jqXHR.status === 429) {
            timeoutMs = 2000;
            removeLoading = false;
            loadingQueue.unshift({ url, refresh, $elem, categoryId, topicId });
          } else {
            setFailedCache(normalize(url), true);
          }
        }
      )
      .finally(() => {
        timeout = later(() => loadNext(ajax), timeoutMs);
        if (removeLoading) {
          $elem.removeClass(LOADING_ONEBOX_CSS_CLASS);
          $elem.data("onebox-loaded");
        }
      });
  }
  
  // Perform a lookup of a onebox based an anchor $element.
  // It will insert a loading indicator and remove it when the loading is complete or fails.
  export function load({
    elem,
    refresh = true,
    ajax,
    synchronous = false,
    categoryId,
    topicId
  }) {
    const $elem = $(elem);
  
    // If the onebox has loaded or is loading, return
    if ($elem.data("onebox-loaded")) return;
    if ($elem.hasClass(LOADING_ONEBOX_CSS_CLASS)) return;
  
    const url = elem.href;
  
    // Unless we're forcing a refresh...
    if (!refresh) {
      // If we have it in our cache, return it.
      const cached = localCache[normalize(url)];
      if (cached) return cached.prop("outerHTML");
  
      // If the request failed, don't do anything
      const failed = failedCache[normalize(url)];
      if (failed) return;
    }
  
    // Add the loading CSS class
    $elem.addClass(LOADING_ONEBOX_CSS_CLASS);
  
    // Add to the loading queue
    loadingQueue.push({ url, refresh, $elem, categoryId, topicId });
  
    // Load next url in queue
    if (synchronous) {
      return loadNext(ajax);
    } else {
      timeout = timeout || later(() => loadNext(ajax), 150);
    }
  }
  