/* 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, {
  NewTabUtils: "resource://gre/modules/NewTabUtils.sys.mjs",
});

/**
 * Get the URLs with the top frecency scores.
 *
 * Note:
 *   - Blocked URLs are excluded
 *   - Allow multiple URLs from the same domain (www vs non-www urls)
 *
 * @param {number} maxUrls
 *   The maximum number of URLs to fetch.
 * @param {number} frecencyThreshold
 *   The minimal frecency score of the URL. Will use the default set by
 *   the upstream module if unspecified. For reference, "100" means one
 *   visit in the past 3 days. see more details at:
 *   `/browser/components/urlbar/docs/ranking.rst`
 * @returns {Array}
 *   An array of URLs. Note that the actual number could be less than `maxUrls`.
 */
export async function getTopFrecentUrls(
  maxUrls,
  frecencyThreshold /* for test */
) {
  const options = {
    ignoreBlocked: true,
    onePerDomain: false,
    includeFavicon: false,
    topsiteFrecency: frecencyThreshold,
    numItems: maxUrls,
  };
  const records =
    await lazy.NewTabUtils.activityStreamLinks.getTopSites(options);

  return records.map(site => site.url);
}

/**
 * Get the URLs of the most recent browsing history.
 *
 * Note:
 *   - Blocked URLs are excluded
 *   - Recent bookmarks are excluded
 *   - Recent "Save-to-Pocket" URLs are excluded
 *   - It would only return URLs if the page meta data is present. We can relax
 *     this in the future.
 *   - Multiple URLs may be returned for the same domain
 *
 * @param {number} maxUrls
 *   The maximum number of URLs to fetch.
 * @returns {Array}
 *   An array of URLs. Note that the actual number could be less than `maxUrls`.
 */
export async function getMostRecentUrls(maxUrls) {
  const options = {
    ignoreBlocked: true,
    excludeBookmarks: true,
    excludeHistory: false,
    excludePocket: true,
    withFavicons: false,
    numItems: maxUrls,
  };
  const records =
    await lazy.NewTabUtils.activityStreamLinks.getHighlights(options);

  return records.map(site => site.url);
}

/**
 * Get the URLs as a combination of the top frecent and the most recent
 * browsing history.
 *
 * It will fetch `maxUrls` URLs from top frecent URLs and use most recent URLs
 * as a fallback if the former is insufficient. Duplicates will be removed
 * As a result, the returned URLs might be fewer than requested.
 *
 * @param {number} maxUrls
 *   The maximum number of URLs to fetch.
 * @returns {Array}
 *   An array of URLs.
 */
export async function getFrecentRecentCombinedUrls(maxUrls) {
  let urls = await getTopFrecentUrls(maxUrls);
  if (urls.length < maxUrls) {
    const n = Math.round((maxUrls - urls.length) * 1.2); // Over-fetch for deduping
    const recentUrls = await getMostRecentUrls(n);
    urls = dedupUrls(urls, recentUrls).slice(0, maxUrls);
  }

  return urls;
}

/**
 * A helper to deduplicate items from any number of grouped URLs.
 *
 * Note:
 *   - Currently, all the elements (URLs) of the input arrays are treated as keys.
 *   - It doesn't assume the uniqueness within the group, therefore, in-group
 *     duplicates will be deduped as well.
 *
 * @param {Array} groups
 *   Contains an arbitrary number of arrays of URLs.
 * @returns {Array}
 *   An array of unique URLs from the input groups.
 */
function dedupUrls(...groups) {
  const uniques = new Set(groups.flat());
  return [...uniques];
}
