/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

const lazy = {};

ChromeUtils.defineESModuleGetters(
  lazy,
  {
    NetworkHelper:
      "resource://devtools/shared/network-observer/NetworkHelper.sys.mjs",
  },
  { global: "contextual" }
);

/**
 * Global cache session object.
 */
let gCacheSession = null;

/**
 * Get (and create if necessary) a cache session / cache storage session.
 *
 * @param {nsIRequest} request
 */
function getCacheSession(request) {
  if (!gCacheSession) {
    try {
      const cacheService = Services.cache2;
      if (cacheService) {
        let loadContext = lazy.NetworkHelper.getRequestLoadContext(request);
        if (!loadContext) {
          // Get default load context if we can't fetch.
          loadContext = Services.loadContextInfo.default;
        }
        gCacheSession = cacheService.diskCacheStorage(loadContext);
      }
    } catch (e) {
      gCacheSession = null;
    }
  }

  return gCacheSession;
}

/**
 * Parses a cache entry returned from the backend to build a response cache
 * object.
 *
 * @param {nsICacheEntry} cacheEntry
 *     The cache entry from the backend.
 *
 * @returns {object}
 *     A responseCache object expected by RDP.
 */
function buildResponseCacheObject(cacheEntry) {
  const cacheObject = {};
  try {
    if (cacheEntry.storageDataSize) {
      cacheObject.storageDataSize = cacheEntry.storageDataSize;
    }
  } catch (e) {
    // We just need to handle this in case it's a js file of 0B.
  }
  if (cacheEntry.expirationTime) {
    cacheObject.expirationTime = cacheEntry.expirationTime;
  }
  if (cacheEntry.fetchCount) {
    cacheObject.fetchCount = cacheEntry.fetchCount;
  }
  if (cacheEntry.lastFetched) {
    cacheObject.lastFetched = cacheEntry.lastFetched;
  }
  if (cacheEntry.lastModified) {
    cacheObject.lastModified = cacheEntry.lastModified;
  }
  if (cacheEntry.deviceID) {
    cacheObject.deviceID = cacheEntry.deviceID;
  }
  return cacheObject;
}

/**
 * Does the fetch for the cache entry from the session.
 *
 * @param {nsIRequest} request
 *     The request object.
 *
 * @returns {Promise}
 *     Promise which resolve a response cache object object, or null if none
 *     was available.
 */
export function getResponseCacheObject(request) {
  const cacheSession = getCacheSession(request);
  if (!cacheSession) {
    return Promise.resolve(null);
  }

  return new Promise(resolve => {
    cacheSession.asyncOpenURI(
      request.URI,
      "",
      Ci.nsICacheStorage.OPEN_SECRETLY,
      {
        onCacheEntryCheck: () => {
          return Ci.nsICacheEntryOpenCallback.ENTRY_WANTED;
        },
        onCacheEntryAvailable: cacheEntry => {
          if (cacheEntry) {
            const cacheObject = buildResponseCacheObject(cacheEntry);
            resolve(cacheObject);
          } else {
            resolve(null);
          }
        },
      }
    );
  });
}
