"use strict";

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

// This test checks whether the theme experiments work
add_task(async function test_experiment_static_theme() {
  let extension = ExtensionTestUtils.loadExtension({
    useAddonManager: "temporary",
    manifest: {
      theme: {
        colors: {
          some_color_property: "#ff00ff",
        },
        images: {
          some_image_property: "background.jpg",
        },
        properties: {
          some_random_property: "no-repeat",
        },
      },
      theme_experiment: {
        colors: {
          some_color_property: "--some-color-property",
        },
        images: {
          some_image_property: "--some-image-property",
        },
        properties: {
          some_random_property: "--some-random-property",
        },
      },
    },
  });

  const root = window.document.documentElement;

  is(
    root.style.getPropertyValue("--some-color-property"),
    "",
    "Color property should be unset"
  );
  is(
    root.style.getPropertyValue("--some-image-property"),
    "",
    "Image property should be unset"
  );
  is(
    root.style.getPropertyValue("--some-random-property"),
    "",
    "Generic Property should be unset."
  );

  await extension.startup();

  const testExperimentApplied = rootEl => {
    if (AddonSettings.EXPERIMENTS_ENABLED) {
      is(
        rootEl.style.getPropertyValue("--some-color-property"),
        hexToCSS("#ff00ff"),
        "Color property should be parsed and set."
      );
      ok(
        rootEl.style
          .getPropertyValue("--some-image-property")
          .startsWith("url("),
        "Image property should be parsed."
      );
      ok(
        rootEl.style
          .getPropertyValue("--some-image-property")
          .endsWith("background.jpg)"),
        "Image property should be set."
      );
      is(
        rootEl.style.getPropertyValue("--some-random-property"),
        "no-repeat",
        "Generic Property should be set."
      );
    } else {
      is(
        rootEl.style.getPropertyValue("--some-color-property"),
        "",
        "Color property should be unset"
      );
      is(
        rootEl.style.getPropertyValue("--some-image-property"),
        "",
        "Image property should be unset"
      );
      is(
        rootEl.style.getPropertyValue("--some-random-property"),
        "",
        "Generic Property should be unset."
      );
    }
  };

  info("Testing that current window updated with the experiment applied");
  testExperimentApplied(root);

  info("Testing that new window initialized with the experiment applied");
  const newWindow = await BrowserTestUtils.openNewBrowserWindow();
  const newWindowRoot = newWindow.document.documentElement;
  testExperimentApplied(newWindowRoot);

  await extension.unload();

  info("Testing that both windows unapplied the experiment");
  for (const rootEl of [root, newWindowRoot]) {
    is(
      rootEl.style.getPropertyValue("--some-color-property"),
      "",
      "Color property should be unset"
    );
    is(
      rootEl.style.getPropertyValue("--some-image-property"),
      "",
      "Image property should be unset"
    );
    is(
      rootEl.style.getPropertyValue("--some-random-property"),
      "",
      "Generic Property should be unset."
    );
  }
  await BrowserTestUtils.closeWindow(newWindow);
});

add_task(async function test_experiment_dynamic_theme() {
  let extension = ExtensionTestUtils.loadExtension({
    useAddonManager: "temporary",
    manifest: {
      permissions: ["theme"],
      theme_experiment: {
        colors: {
          some_color_property: "--some-color-property",
        },
        images: {
          some_image_property: "--some-image-property",
        },
        properties: {
          some_random_property: "--some-random-property",
        },
      },
    },
    background() {
      const theme = {
        colors: {
          some_color_property: "#ff00ff",
        },
        images: {
          some_image_property: "background.jpg",
        },
        properties: {
          some_random_property: "no-repeat",
        },
      };
      browser.test.onMessage.addListener(msg => {
        if (msg === "update-theme") {
          browser.theme.update(theme).then(() => {
            browser.test.sendMessage("theme-updated");
          });
        } else {
          browser.theme.reset().then(() => {
            browser.test.sendMessage("theme-reset");
          });
        }
      });
    },
  });

  await extension.startup();

  const root = window.document.documentElement;

  is(
    root.style.getPropertyValue("--some-color-property"),
    "",
    "Color property should be unset"
  );
  is(
    root.style.getPropertyValue("--some-image-property"),
    "",
    "Image property should be unset"
  );
  is(
    root.style.getPropertyValue("--some-random-property"),
    "",
    "Generic Property should be unset."
  );

  extension.sendMessage("update-theme");
  await extension.awaitMessage("theme-updated");

  const testExperimentApplied = rootEl => {
    if (AddonSettings.EXPERIMENTS_ENABLED) {
      is(
        rootEl.style.getPropertyValue("--some-color-property"),
        hexToCSS("#ff00ff"),
        "Color property should be parsed and set."
      );
      ok(
        rootEl.style
          .getPropertyValue("--some-image-property")
          .startsWith("url("),
        "Image property should be parsed."
      );
      ok(
        rootEl.style
          .getPropertyValue("--some-image-property")
          .endsWith("background.jpg)"),
        "Image property should be set."
      );
      is(
        rootEl.style.getPropertyValue("--some-random-property"),
        "no-repeat",
        "Generic Property should be set."
      );
    } else {
      is(
        rootEl.style.getPropertyValue("--some-color-property"),
        "",
        "Color property should be unset"
      );
      is(
        rootEl.style.getPropertyValue("--some-image-property"),
        "",
        "Image property should be unset"
      );
      is(
        rootEl.style.getPropertyValue("--some-random-property"),
        "",
        "Generic Property should be unset."
      );
    }
  };
  testExperimentApplied(root);

  const newWindow = await BrowserTestUtils.openNewBrowserWindow();
  const newWindowRoot = newWindow.document.documentElement;

  testExperimentApplied(newWindowRoot);

  extension.sendMessage("reset-theme");
  await extension.awaitMessage("theme-reset");

  for (const rootEl of [root, newWindowRoot]) {
    is(
      rootEl.style.getPropertyValue("--some-color-property"),
      "",
      "Color property should be unset"
    );
    is(
      rootEl.style.getPropertyValue("--some-image-property"),
      "",
      "Image property should be unset"
    );
    is(
      rootEl.style.getPropertyValue("--some-random-property"),
      "",
      "Generic Property should be unset."
    );
  }

  extension.sendMessage("update-theme");
  await extension.awaitMessage("theme-updated");

  testExperimentApplied(root);
  testExperimentApplied(newWindowRoot);

  await extension.unload();

  for (const rootEl of [root, newWindowRoot]) {
    is(
      rootEl.style.getPropertyValue("--some-color-property"),
      "",
      "Color property should be unset"
    );
    is(
      rootEl.style.getPropertyValue("--some-image-property"),
      "",
      "Image property should be unset"
    );
    is(
      rootEl.style.getPropertyValue("--some-random-property"),
      "",
      "Generic Property should be unset."
    );
  }

  await BrowserTestUtils.closeWindow(newWindow);
});

add_task(async function test_experiment_stylesheet() {
  let extension = ExtensionTestUtils.loadExtension({
    useAddonManager: "temporary",
    manifest: {
      theme: {
        colors: {
          menu_button_background: "#ff00ff",
        },
      },
      theme_experiment: {
        stylesheet: "experiment.css",
        colors: {
          menu_button_background: "--menu-button-background",
        },
      },
    },
    files: {
      "experiment.css": `#PanelUI-menu-button {
        background-color: var(--menu-button-background);
        fill: white;
      }`,
    },
  });

  const root = window.document.documentElement;
  const menuButton = document.getElementById("PanelUI-menu-button");
  const computedStyle = window.getComputedStyle(menuButton);
  const expectedColor = hexToCSS("#ff00ff");
  const expectedFill = hexToCSS("#ffffff");

  is(
    root.style.getPropertyValue("--menu-button-background"),
    "",
    "Variable should be unset"
  );
  isnot(
    computedStyle.backgroundColor,
    expectedColor,
    "Menu button should not have custom background"
  );
  isnot(
    computedStyle.fill,
    expectedFill,
    "Menu button should not have stylesheet fill"
  );

  await extension.startup();

  if (AddonSettings.EXPERIMENTS_ENABLED) {
    // Wait for stylesheet load.
    await TestUtils.waitForCondition(() => computedStyle.fill === expectedFill);

    is(
      root.style.getPropertyValue("--menu-button-background"),
      expectedColor,
      "Variable should be parsed and set."
    );
    is(
      computedStyle.backgroundColor,
      expectedColor,
      "Menu button should be have correct background"
    );
    is(
      computedStyle.fill,
      expectedFill,
      "Menu button should be have correct fill"
    );
  } else {
    is(
      root.style.getPropertyValue("--menu-button-background"),
      "",
      "Variable should be unset"
    );
    isnot(
      computedStyle.backgroundColor,
      expectedColor,
      "Menu button should not have custom background"
    );
    isnot(
      computedStyle.fill,
      expectedFill,
      "Menu button should not have stylesheet fill"
    );
  }

  await extension.unload();

  is(
    root.style.getPropertyValue("--menu-button-background"),
    "",
    "Variable should be unset"
  );
  isnot(
    computedStyle.backgroundColor,
    expectedColor,
    "Menu button should not have custom background"
  );
  isnot(
    computedStyle.fill,
    expectedFill,
    "Menu button should not have stylesheet fill"
  );
});

// This test checks whether the theme experiments are allowed for non privileged
// theme installed non-temporarily if AddonSettings.EXPERIMENTS_ENABLED is true.
add_task(async function test_experiment_installed_non_temporarily() {
  await SpecialPowers.pushPrefEnv({
    set: [["extensions.experiments.enabled", true]],
  });

  if (!AddonSettings.EXPERIMENTS_ENABLED) {
    info(
      "Skipping test case on build where AddonSettings.EXPERIMENTS_ENABLED is false"
    );
    return;
  }

  let extension = ExtensionTestUtils.loadExtension({
    manifest: {
      theme: {
        colors: {
          some_color_property: "#ff00ff",
        },
      },
      theme_experiment: {
        colors: {
          some_color_property: "--some-color-property",
        },
      },
    },
  });

  const root = window.document.documentElement;

  is(
    root.style.getPropertyValue("--some-color-property"),
    "",
    "Color property should be unset"
  );

  await extension.startup();

  is(
    root.style.getPropertyValue("--some-color-property"),
    hexToCSS("#ff00ff"),
    "Color property should be parsed and set."
  );

  await extension.unload();

  await SpecialPowers.popPrefEnv();
});
