/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
/* vim: set sts=2 sw=2 et tw=80: */
"use strict";

add_setup(async function () {
  // The page action button is hidden by default.
  // This tests the use of pageAction when the button is visible.
  //
  // TODO(Bug 1704171): this should technically be removed in a follow up
  // and the tests in this file adapted to keep into account that:
  // - The pageAction is pinned on the urlbar by default
  //   when shown, and hidden when is not available (same for the
  //   overflow menu when enabled)
  BrowserPageActions.mainButtonNode.style.visibility = "visible";
  registerCleanupFunction(() => {
    BrowserPageActions.mainButtonNode.style.removeProperty("visibility");
  });
});

async function test_clickData(testAsNonPersistent = false) {
  let extension = ExtensionTestUtils.loadExtension({
    manifest: {
      page_action: {},
      background: {
        persistent: !testAsNonPersistent,
        scripts: ["background.js"],
      },
    },

    files: {
      "background.js": async function background() {
        function onClicked(_tab, info) {
          let button = info.button;
          let modifiers = info.modifiers;
          browser.test.sendMessage("onClick", { button, modifiers });
        }

        browser.pageAction.onClicked.addListener(onClicked);

        let [tab] = await browser.tabs.query({
          active: true,
          currentWindow: true,
        });
        await browser.pageAction.show(tab.id);
        browser.test.sendMessage("ready");
      },
    },
  });

  const map = {
    shiftKey: "Shift",
    altKey: "Alt",
    metaKey: "Command",
    ctrlKey: "Ctrl",
  };

  function assertSingleModifier(info, modifier) {
    if (modifier === "ctrlKey" && AppConstants.platform === "macosx") {
      is(
        info.modifiers.length,
        2,
        `MacCtrl modifier with control click on Mac`
      );
      is(
        info.modifiers[1],
        "MacCtrl",
        `MacCtrl modifier with control click on Mac`
      );
    } else {
      is(
        info.modifiers.length,
        1,
        `No unnecessary modifiers for exactly one key on event`
      );
    }

    is(info.modifiers[0], map[modifier], `Correct modifier on click event`);
  }

  async function testClickPageAction(doClick, doEnterKey) {
    for (let modifier of Object.keys(map)) {
      for (let i = 0; i < 2; i++) {
        let clickEventData = { button: i };
        clickEventData[modifier] = true;
        await doClick(extension, window, clickEventData);
        let info = await extension.awaitMessage("onClick");

        is(info.button, i, `Correct button on click event`);
        assertSingleModifier(info, modifier);
      }

      let keypressEventData = {};
      keypressEventData[modifier] = true;
      await doEnterKey(extension, keypressEventData);
      let info = await extension.awaitMessage("onClick");

      is(info.button, 0, `Key command emulates left click`);
      assertSingleModifier(info, modifier);
    }
  }

  await extension.startup();
  await extension.awaitMessage("ready");

  if (testAsNonPersistent) {
    assertPersistentListeners(extension, "pageAction", "onClicked", {
      primed: false,
    });
    info("Terminating the background event page");
    await extension.terminateBackground();
    assertPersistentListeners(extension, "pageAction", "onClicked", {
      primed: true,
    });
  }

  info("Clicking the pageAction");
  await testClickPageAction(clickPageAction, triggerPageActionWithKeyboard);

  if (testAsNonPersistent) {
    await extension.awaitMessage("ready");
    assertPersistentListeners(extension, "pageAction", "onClicked", {
      primed: false,
    });
  }

  await testClickPageAction(
    clickPageActionInPanel,
    triggerPageActionWithKeyboardInPanel
  );

  await extension.unload();
}

async function test_clickData_reset(testAsNonPersistent = false) {
  let extension = ExtensionTestUtils.loadExtension({
    manifest: {
      browser_action: {
        default_area: "navbar",
      },
      page_action: {},
      background: {
        persistent: !testAsNonPersistent,
        scripts: ["background.js"],
      },
    },

    files: {
      "background.js": async function background() {
        function onBrowserActionClicked(tab, info) {
          // openPopup requires user interaction, such as a browser action click.
          browser.pageAction.openPopup();
        }

        function onPageActionClicked(tab, info) {
          browser.test.sendMessage("onClick", info);
        }

        browser.browserAction.onClicked.addListener(onBrowserActionClicked);
        browser.pageAction.onClicked.addListener(onPageActionClicked);

        let [tab] = await browser.tabs.query({
          active: true,
          currentWindow: true,
        });
        await browser.pageAction.show(tab.id);
        browser.test.sendMessage("ready");
      },
    },
  });

  async function clickPageActionWithModifiers() {
    await clickPageAction(extension, window, { button: 1, shiftKey: true });
    let info = await extension.awaitMessage("onClick");
    is(info.button, 1);
    is(info.modifiers[0], "Shift");
  }

  function assertInfoReset(info) {
    is(info.button, 0, `ClickData button reset properly`);
    is(info.modifiers.length, 0, `ClickData modifiers reset properly`);
  }

  await extension.startup();
  await extension.awaitMessage("ready");

  if (testAsNonPersistent) {
    assertPersistentListeners(extension, "pageAction", "onClicked", {
      primed: false,
    });
    info("Terminating the background event page");
    await extension.terminateBackground();
    assertPersistentListeners(extension, "pageAction", "onClicked", {
      primed: true,
    });
  }

  info("Clicking the pageAction");
  await clickPageActionWithModifiers();

  if (testAsNonPersistent) {
    await extension.awaitMessage("ready");
    assertPersistentListeners(extension, "pageAction", "onClicked", {
      primed: false,
    });
  }

  await clickBrowserAction(extension);
  assertInfoReset(await extension.awaitMessage("onClick"));

  await clickPageActionWithModifiers();

  await triggerPageActionWithKeyboard(extension);
  assertInfoReset(await extension.awaitMessage("onClick"));

  await extension.unload();
}

add_task(function test_clickData_MV2() {
  return test_clickData(/* testAsNonPersistent */ false);
});

add_task(async function test_clickData_MV2_eventPage() {
  await SpecialPowers.pushPrefEnv({
    set: [["extensions.eventPages.enabled", true]],
  });
  await test_clickData(/* testAsNonPersistent */ true);
  await SpecialPowers.popPrefEnv();
});

add_task(function test_clickData_reset_MV2() {
  return test_clickData_reset(/* testAsNonPersistent */ false);
});

add_task(async function test_clickData_reset_MV2_eventPage() {
  await SpecialPowers.pushPrefEnv({
    set: [["extensions.eventPages.enabled", true]],
  });
  await test_clickData_reset(/* testAsNonPersistent */ true);
  await SpecialPowers.popPrefEnv();
});
