/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

function support(feature) {
  if (typeof document === 'undefined') {
    return false;
  }

  const fakeLink = document.createElement('link');
  try {
    if (fakeLink.relList && typeof fakeLink.relList.supports === 'function') {
      return fakeLink.relList.supports(feature);
    }
  } catch (err) {
    return false;
  }

  return false;
}

function linkPrefetchStrategy(url: string) {
  return new Promise((resolve, reject) => {
    if (typeof document === 'undefined') {
      reject();
      return;
    }

    const link = document.createElement('link');
    link.setAttribute('rel', 'prefetch');
    link.setAttribute('href', url);

    link.onload = resolve;
    link.onerror = reject;

    const parentElement =
      document.getElementsByTagName('head')[0] ||
      document.getElementsByName('script')[0].parentNode;
    parentElement.appendChild(link);
  });
}

function xhrPrefetchStrategy(url: string) {
  return new Promise((resolve, reject) => {
    const req = new XMLHttpRequest();
    req.open('GET', url, true);
    req.withCredentials = true;

    req.onload = () => {
      if (req.status === 200) {
        resolve();
      } else {
        reject();
      }
    };

    req.send(null);
  });
}

const supportedPrefetchStrategy = support('prefetch')
  ? linkPrefetchStrategy
  : xhrPrefetchStrategy;

const preFetched = {};

function prefetch(url: string): Promise<void> {
  return new Promise((resolve) => {
    if (preFetched[url]) {
      resolve();
      return;
    }

    supportedPrefetchStrategy(url)
      .then(() => {
        resolve();
        preFetched[url] = true;
      })
      // eslint-disable-next-line @typescript-eslint/no-empty-function
      .catch(() => {}); // 404s are logged to the console anyway.
  });
}

export default prefetch;
