/* Any copyright is dedicated to the Public Domain.
 * http://creativecommons.org/publicdomain/zero/1.0/
 */

/* eslint max-len: ["error", 80] */

/* exported DISCOAPI_DEFAULT_FIXTURE, getCardContainer,
            getDiscoveryElement, promiseAddonInstall, promiseDiscopaneUpdate,
            promiseEvent, promiseObserved, readAPIResponseFixture */

/* globals RELATIVE_DIR, promisePopupNotificationShown,
           waitAppMenuNotificationShown */

"use strict";

const { AddonTestUtils } = ChromeUtils.importESModule(
  "resource://testing-common/AddonTestUtils.sys.mjs"
);

const {
  ExtensionUtils: { promiseEvent, promiseObserved },
} = ChromeUtils.importESModule("resource://gre/modules/ExtensionUtils.sys.mjs");

AddonTestUtils.initMochitest(this);

// The response to the discovery API, as documented at:
// https://addons-server.readthedocs.io/en/latest/topics/api/discovery.html
//
// The tests using this fixure are meant to verify that the discopane works
// with the latest AMO API.
// The following fixure file should be kept in sync with the content of
// latest AMO API response, e.g. from
//
// https://addons.allizom.org/api/v4/discovery/?lang=en-US
//
// The response must contain at least one theme, and one extension.
const DISCOAPI_DEFAULT_FIXTURE = PathUtils.join(
  Services.dirsvc.get("CurWorkD", Ci.nsIFile).path,
  ...RELATIVE_DIR.split("/"),
  "discovery",
  "api_response.json"
);

// Read the content of API_RESPONSE_FILE, and replaces any embedded URLs with
// URLs that point to the `amoServer` test server.
async function readAPIResponseFixture(
  amoTestHost,
  fixtureFilePath = DISCOAPI_DEFAULT_FIXTURE
) {
  let apiText = await IOUtils.readUTF8(fixtureFilePath);
  apiText = apiText.replace(/\bhttps?:\/\/[^"]+(?=")/g, url => {
    try {
      url = new URL(url);
    } catch (e) {
      // Responses may contain "http://*/*"; ignore it.
      return url;
    }
    // In this test, we only need to distinguish between different file types,
    // so just use the file extension as path name for amoServer.
    let ext = url.pathname.split(".").pop();
    return `http://${amoTestHost}/${ext}?${url.pathname}${url.search}`;
  });

  return apiText;
}

// Wait until the current `<discovery-pane>` element has finished loading its
// cards. This can be used after the cards have been loaded.
function promiseDiscopaneUpdate(win) {
  let { cardsReady } = getCardContainer(win);
  ok(cardsReady, "Discovery cards should have started to initialize");
  return cardsReady;
}

function getCardContainer(win) {
  return getDiscoveryElement(win).querySelector("recommended-addon-list");
}

function getDiscoveryElement(win) {
  return win.document.querySelector("discovery-pane");
}

// A helper that waits until an installation has been requested from `amoServer`
// and proceeds with approving the installation.
async function promiseAddonInstall(
  amoServer,
  extensionData,
  expectedTelemetryInfo = { source: "disco", taarRecommended: false }
) {
  let description = extensionData.manifest.description;
  let xpiFile = AddonTestUtils.createTempWebExtensionFile(extensionData);
  amoServer.registerFile("/xpi", xpiFile);

  let addonId =
    extensionData.manifest?.browser_specific_settings?.gecko?.id ||
    extensionData.manifest?.applications?.gecko?.id;
  let installedPromise = waitAppMenuNotificationShown(
    extensionData.manifest?.theme ? "theme-installed" : "addon-installed",
    addonId,
    true
  );

  if (!extensionData.manifest.theme) {
    info(`${description}: Waiting for permission prompt`);
    // Extensions have install prompts.
    let panel = await promisePopupNotificationShown("addon-webext-permissions");
    panel.button.click();
  } else {
    info(`${description}: Waiting for install prompt`);
    let panel = await promisePopupNotificationShown(
      "addon-install-confirmation"
    );
    panel.button.click();
  }

  info("Waiting for post-install doorhanger");
  await installedPromise;

  let addon = await AddonManager.getAddonByID(addonId);
  Assert.deepEqual(
    addon.installTelemetryInfo,
    expectedTelemetryInfo,
    "The installed add-on should have the expected telemetry info"
  );
}
