"use strict";

const { ASRouter } = ChromeUtils.importESModule(
  "resource:///modules/asrouter/ASRouter.sys.mjs"
);
const { AddonRepository } = ChromeUtils.importESModule(
  "resource://gre/modules/addons/AddonRepository.sys.mjs"
);
const { ExperimentFakes } = ChromeUtils.importESModule(
  "resource://testing-common/NimbusTestUtils.sys.mjs"
);

const TEST_ADDON_INFO = [
  {
    name: "Test Add-on",
    sourceURI: { scheme: "https", spec: "https://test.xpi" },
    icons: { 32: "test.png", 64: "test.png" },
    type: "extension",
  },
];

const TEST_ADDON_INFO_THEME = [
  {
    name: "Test Add-on",
    sourceURI: { scheme: "https", spec: "https://test.xpi" },
    icons: { 32: "test.png", 64: "test.png" },
    screenshots: [{ url: "test.png" }],
    type: "theme",
  },
];

async function openRTAMOWelcomePage() {
  // Can't properly stub the child/parent actors so instead
  // we stub the modules they depend on for the RTAMO flow
  // to ensure the right thing is rendered.
  await ASRouter.forceAttribution({
    source: "addons.mozilla.org",
    medium: "referral",
    campaign: "non-fx-button",
    // with the sinon override, the id doesn't matter
    content: "rta:whatever",
    experiment: "ua-onboarding",
    variation: "chrome",
    ua: "Google Chrome 123",
    dltoken: "00000000-0000-0000-0000-000000000000",
  });

  let tab = await BrowserTestUtils.openNewForegroundTab(
    gBrowser,
    "about:welcome",
    true
  );

  registerCleanupFunction(async () => {
    BrowserTestUtils.removeTab(tab);
    // Clear cache call is only possible in a testing environment
    Services.env.set("XPCSHELL_TEST_PROFILE_DIR", "testing");
    await ASRouter.forceAttribution({
      source: "",
      medium: "",
      campaign: "",
      content: "",
      experiment: "",
      variation: "",
      ua: "",
      dltoken: "",
    });
  });

  return tab.linkedBrowser;
}

/**
 * Setup and test RTAMO welcome UI
 */
async function test_screen_content(
  browser,
  experiment,
  expectedSelectors = [],
  unexpectedSelectors = []
) {
  await ContentTask.spawn(
    browser,
    { expectedSelectors, experiment, unexpectedSelectors },
    async ({
      expectedSelectors: expected,
      experiment: experimentName,
      unexpectedSelectors: unexpected,
    }) => {
      for (let selector of expected) {
        await ContentTaskUtils.waitForCondition(
          () => content.document.querySelector(selector),
          `Should render ${selector} in ${experimentName}`
        );
      }
      for (let selector of unexpected) {
        ok(
          !content.document.querySelector(selector),
          `Should not render ${selector} in ${experimentName}`
        );
      }
    }
  );
}

async function onButtonClick(browser, elementId) {
  await ContentTask.spawn(
    browser,
    { elementId },
    async ({ elementId: buttonId }) => {
      await ContentTaskUtils.waitForCondition(
        () => content.document.querySelector(buttonId),
        buttonId
      );
      let button = content.document.querySelector(buttonId);
      button.click();
    }
  );
}

/**
 * Test the RTAMO welcome UI
 */
add_task(async function test_rtamo_aboutwelcome() {
  let sandbox = sinon.createSandbox();
  sandbox.stub(AddonRepository, "getAddonsByIDs").resolves(TEST_ADDON_INFO);

  let browser = await openRTAMOWelcomePage();

  await test_screen_content(
    browser,
    "RTAMO UI",
    // Expected selectors:
    [
      `div.onboardingContainer[style*='background: var(--mr-welcome-background-color) var(--mr-welcome-background-gradient)']`,
      "h2[data-l10n-id='mr1-return-to-amo-addon-title']",
      `h2[data-l10n-args='{"addon-name":"${TEST_ADDON_INFO[0].name}"}'`,
      "div.rtamo-icon",
      "button.primary[data-l10n-id='mr1-return-to-amo-add-extension-label']",
      "button[data-l10n-id='onboarding-not-now-button-label']",
    ],
    // Unexpected selectors:
    [
      "main.AW_STEP1",
      "main.AW_STEP2",
      "main.AW_STEP3",
      "div.tiles-container.info",
    ]
  );

  await onButtonClick(
    browser,
    "button[data-l10n-id='onboarding-not-now-button-label']"
  );
  Assert.ok(gURLBar.focused, "Focus should be on awesome bar");

  let windowGlobalParent = browser.browsingContext.currentWindowGlobal;
  let aboutWelcomeActor = windowGlobalParent.getActor("AboutWelcome");
  const messageSandbox = sinon.createSandbox();
  // Stub AboutWelcomeParent Content Message Handler
  messageSandbox.stub(aboutWelcomeActor, "onContentMessage");
  registerCleanupFunction(() => {
    messageSandbox.restore();
  });

  await onButtonClick(browser, "button.primary");
  const { callCount } = aboutWelcomeActor.onContentMessage;
  Assert.strictEqual(
    callCount,
    2,
    `${callCount} Stub called twice to install extension and send telemetry`
  );

  const installExtensionCall = aboutWelcomeActor.onContentMessage.getCall(0);
  Assert.equal(
    installExtensionCall.args[0],
    "AWPage:SPECIAL_ACTION",
    "send special action to install add on"
  );
  Assert.equal(
    installExtensionCall.args[1].type,
    "INSTALL_ADDON_FROM_URL",
    "Special action type is INSTALL_ADDON_FROM_URL"
  );
  Assert.equal(
    installExtensionCall.args[1].data.url,
    "https://test.xpi",
    "Install add on url"
  );
  Assert.equal(
    installExtensionCall.args[1].data.telemetrySource,
    "rtamo",
    "Install add on telemetry source"
  );
  const telemetryCall = aboutWelcomeActor.onContentMessage.getCall(1);
  Assert.equal(
    telemetryCall.args[0],
    "AWPage:TELEMETRY_EVENT",
    "send add extension telemetry"
  );
  Assert.equal(
    telemetryCall.args[1].event,
    "CLICK_BUTTON",
    "Telemetry event sent as INSTALL"
  );
  Assert.equal(
    telemetryCall.args[1].event_context.source,
    "ADD_EXTENSION_BUTTON",
    "Source of the event is Add Extension Button"
  );
  Assert.equal(
    telemetryCall.args[1].message_id,
    "RTAMO_DEFAULT_WELCOME_EXTENSION",
    "Message Id sent in telemetry for default RTAMO"
  );

  sandbox.restore();
});

add_task(async function test_rtamo_over_experiments() {
  let sandbox = sinon.createSandbox();
  sandbox.stub(AddonRepository, "getAddonsByIDs").resolves(TEST_ADDON_INFO);

  let doExperimentCleanup = await ExperimentFakes.enrollWithFeatureConfig({
    featureId: "aboutwelcome",
    value: { screens: [], enabled: true },
  });

  let browser = await openRTAMOWelcomePage();

  // If addon attribution exist, we should see RTAMO even if enrolled
  // in about:welcome experiment
  await test_screen_content(
    browser,
    "Experiment RTAMO UI",
    // Expected selectors:
    ["h2[data-l10n-id='mr1-return-to-amo-addon-title']"],
    // Unexpected selectors:
    []
  );

  doExperimentCleanup();

  browser = await openRTAMOWelcomePage();

  await test_screen_content(
    browser,
    "No Experiment RTAMO UI",
    // Expected selectors:
    [
      "div.onboardingContainer",
      "h2[data-l10n-id='mr1-return-to-amo-addon-title']",
      "div.rtamo-icon",
      "button.primary",
      "button.secondary",
    ],
    // Unexpected selectors:
    [
      "main.AW_STEP1",
      "main.AW_STEP2",
      "main.AW_STEP3",
      "div.tiles-container.info",
    ]
  );

  sandbox.restore();
});

add_task(async function test_rtamo_primary_button_theme() {
  let themeSandbox = sinon.createSandbox();
  themeSandbox
    .stub(AddonRepository, "getAddonsByIDs")
    .resolves(TEST_ADDON_INFO_THEME);

  let browser = await openRTAMOWelcomePage();

  await test_screen_content(
    browser,
    "RTAMO UI",
    // Expected selectors:
    [
      "div.onboardingContainer",
      "h2[data-l10n-id='mr1-return-to-amo-addon-title']",
      "div.rtamo-icon",
      "button.primary[data-l10n-id='return-to-amo-add-theme-label']",
      "button[data-l10n-id='onboarding-not-now-button-label']",
      "img.rtamo-theme-icon",
    ],
    // Unexpected selectors:
    [
      "main.AW_STEP1",
      "main.AW_STEP2",
      "main.AW_STEP3",
      "div.tiles-container.info",
    ]
  );

  themeSandbox.restore();
});
