"use strict";

const { IndexedDB } = ChromeUtils.importESModule(
  "resource://gre/modules/IndexedDB.sys.mjs"
);

const { AddonRollouts } = ChromeUtils.importESModule(
  "resource://normandy/lib/AddonRollouts.sys.mjs"
);

decorate_task(AddonRollouts.withTestMock(), async function testGetMissing() {
  ok(
    !(await AddonRollouts.get("does-not-exist")),
    "get should return null when the requested rollout does not exist"
  );
});

decorate_task(
  AddonRollouts.withTestMock(),
  async function testAddUpdateAndGet() {
    const rollout = {
      slug: "test-rollout",
      state: AddonRollouts.STATE_ACTIVE,
      extension: {},
    };
    await AddonRollouts.add(rollout);
    let storedRollout = await AddonRollouts.get(rollout.slug);
    Assert.deepEqual(
      rollout,
      storedRollout,
      "get should retrieve a rollout from storage."
    );

    rollout.state = AddonRollouts.STATE_ROLLED_BACK;
    await AddonRollouts.update(rollout);
    storedRollout = await AddonRollouts.get(rollout.slug);
    Assert.deepEqual(
      rollout,
      storedRollout,
      "get should retrieve a rollout from storage."
    );
  }
);

decorate_task(
  AddonRollouts.withTestMock(),
  async function testCantUpdateNonexistent() {
    const rollout = {
      slug: "test-rollout",
      state: AddonRollouts.STATE_ACTIVE,
      extensions: {},
    };
    await Assert.rejects(
      AddonRollouts.update(rollout),
      /doesn't already exist/,
      "Update should fail if the rollout doesn't exist"
    );
    ok(
      !(await AddonRollouts.has("test-rollout")),
      "rollout should not have been added"
    );
  }
);

decorate_task(AddonRollouts.withTestMock(), async function testGetAll() {
  const rollout1 = { slug: "test-rollout-1", extension: {} };
  const rollout2 = { slug: "test-rollout-2", extension: {} };
  await AddonRollouts.add(rollout1);
  await AddonRollouts.add(rollout2);

  const storedRollouts = await AddonRollouts.getAll();
  Assert.deepEqual(
    storedRollouts.sort((a, b) => a.id - b.id),
    [rollout1, rollout2],
    "getAll should return every stored rollout."
  );
});

decorate_task(AddonRollouts.withTestMock(), async function testGetAllActive() {
  const rollout1 = {
    slug: "test-rollout-1",
    state: AddonRollouts.STATE_ACTIVE,
  };
  const rollout3 = {
    slug: "test-rollout-2",
    state: AddonRollouts.STATE_ROLLED_BACK,
  };
  await AddonRollouts.add(rollout1);
  await AddonRollouts.add(rollout3);

  const activeRollouts = await AddonRollouts.getAllActive();
  Assert.deepEqual(
    activeRollouts,
    [rollout1],
    "getAllActive should return only active rollouts"
  );
});

decorate_task(AddonRollouts.withTestMock(), async function testHas() {
  const rollout = { slug: "test-rollout", extensions: {} };
  await AddonRollouts.add(rollout);
  ok(
    await AddonRollouts.has(rollout.slug),
    "has should return true for an existing rollout"
  );
  ok(
    !(await AddonRollouts.has("does not exist")),
    "has should return false for a missing rollout"
  );
});

// init should mark active rollouts in telemetry
decorate_task(
  AddonRollouts.withTestMock(),
  withStub(TelemetryEnvironment, "setExperimentActive"),
  async function testInitTelemetry({ setExperimentActiveStub }) {
    await AddonRollouts.add({
      slug: "test-rollout-active-1",
      state: AddonRollouts.STATE_ACTIVE,
    });
    await AddonRollouts.add({
      slug: "test-rollout-active-2",
      state: AddonRollouts.STATE_ACTIVE,
    });
    await AddonRollouts.add({
      slug: "test-rollout-rolled-back",
      state: AddonRollouts.STATE_ROLLED_BACK,
    });

    await AddonRollouts.init();

    Assert.deepEqual(
      setExperimentActiveStub.args,
      [
        ["test-rollout-active-1", "active", { type: "normandy-addonrollout" }],
        ["test-rollout-active-2", "active", { type: "normandy-addonrollout" }],
      ],
      "init should set activate a telemetry experiment for active addons"
    );
  }
);
