/* 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 { ASRouter } = ChromeUtils.import(
  "resource://activity-stream/lib/ASRouter.jsm"
);
const { RemoteSettings } = ChromeUtils.importESModule(
  "resource://services-settings/remote-settings.sys.mjs"
);
const { RemoteSettingsExperimentLoader } = ChromeUtils.importESModule(
  "resource://nimbus/lib/RemoteSettingsExperimentLoader.sys.mjs"
);
const { ExperimentAPI } = ChromeUtils.importESModule(
  "resource://nimbus/ExperimentAPI.sys.mjs"
);
const { ExperimentFakes, ExperimentTestUtils } = ChromeUtils.importESModule(
  "resource://testing-common/NimbusTestUtils.sys.mjs"
);

const client = RemoteSettings("nimbus-desktop-experiments");

const TEST_MESSAGE_CONTENT = {
  id: "ON_LOAD_TEST_MESSAGE",
  template: "cfr_doorhanger",
  content: {
    bucket_id: "ON_LOAD_TEST_MESSAGE",
    anchor_id: "PanelUI-menu-button",
    layout: "icon_and_message",
    icon: "chrome://browser/content/cfr-lightning.svg",
    icon_dark_theme: "chrome://browser/content/cfr-lightning-dark.svg",
    icon_class: "cfr-doorhanger-small-icon",
    heading_text: "Heading",
    text: "Text",
    buttons: {
      primary: {
        label: { value: "Primary CTA", attributes: { accesskey: "P" } },
        action: { navigate: true },
      },
      secondary: [
        {
          label: { value: "Secondary CTA", attributes: { accesskey: "S" } },
          action: { type: "CANCEL" },
        },
      ],
    },
    skip_address_bar_notifier: true,
  },
  targeting: "true",
  trigger: { id: "messagesLoaded" },
};

add_task(async function test_messagesLoaded_reach_experiment() {
  const sandbox = sinon.createSandbox();
  const sendTriggerSpy = sandbox.spy(ASRouter, "sendTriggerMessage");
  const routeSpy = sandbox.spy(ASRouter, "routeCFRMessage");
  const reachSpy = sandbox.spy(ASRouter, "_recordReachEvent");
  const triggerMatch = sandbox.match({ id: "messagesLoaded" });
  const featureId = "cfr";
  const recipe = ExperimentFakes.recipe(
    `messages_loaded_test_${Services.uuid
      .generateUUID()
      .toString()
      .slice(1, -1)}`,
    {
      id: `messages-loaded-test`,
      bucketConfig: {
        count: 100,
        start: 0,
        total: 100,
        namespace: "mochitest",
        randomizationUnit: "normandy_id",
      },
      branches: [
        {
          slug: "control",
          ratio: 1,
          features: [
            {
              featureId,
              value: { ...TEST_MESSAGE_CONTENT, id: "messages-loaded-test-1" },
            },
          ],
        },
        {
          slug: "treatment",
          ratio: 1,
          features: [
            {
              featureId,
              value: { ...TEST_MESSAGE_CONTENT, id: "messages-loaded-test-2" },
            },
          ],
        },
      ],
    }
  );
  Assert.ok(
    await ExperimentTestUtils.validateExperiment(recipe),
    "Valid recipe"
  );

  await client.db.importChanges({}, Date.now(), [recipe], { clear: true });
  await SpecialPowers.pushPrefEnv({
    set: [
      ["app.shield.optoutstudies.enabled", true],
      ["datareporting.healthreport.uploadEnabled", true],
      [
        "browser.newtabpage.activity-stream.asrouter.providers.messaging-experiments",
        `{"id":"messaging-experiments","enabled":true,"type":"remote-experiments","updateCycleInMs":0}`,
      ],
    ],
  });
  await RemoteSettingsExperimentLoader.updateRecipes();
  await BrowserTestUtils.waitForCondition(
    () => ExperimentAPI.getExperiment({ featureId }),
    "ExperimentAPI should return an experiment"
  );

  await ASRouter._updateMessageProviders();
  await ASRouter.loadMessagesFromAllProviders();

  const filterFn = m =>
    ["messages-loaded-test-1", "messages-loaded-test-2"].includes(m?.id);
  await BrowserTestUtils.waitForCondition(
    () => ASRouter.state.messages.filter(filterFn).length > 1,
    "Should load the test messages"
  );
  Assert.ok(sendTriggerSpy.calledWith(triggerMatch, true), "Trigger fired");
  Assert.ok(
    routeSpy.calledWith(
      sandbox.match(filterFn),
      gBrowser.selectedBrowser,
      triggerMatch
    ),
    "Trigger routed to the correct message"
  );
  Assert.ok(
    reachSpy.calledWith(sandbox.match(filterFn)),
    "Trigger recorded a reach event"
  );
  Assert.ok(
    ASRouter.state.messages.find(m => filterFn(m) && m.forReachEvent)
      ?.forReachEvent.sent,
    "Reach message will not be sent again"
  );

  sandbox.restore();
  await client.db.clear();
  await SpecialPowers.popPrefEnv();
  await ASRouter._updateMessageProviders();
});
