<!DOCTYPE HTML>
<html>
<head>
  <title>action.openPopup Window ID Test</title>
  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
  <script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
  <script type="text/javascript" src="head.js"></script>
  <link rel="stylesheet" href="/tests/SimpleTest/test.css"/>
</head>
<body>

<script type="text/javascript">
"use strict";

let extensionData = {
  manifest: {
    browser_specific_settings: {
      gecko: {
        id: "open-popup@tests.mozilla.org",
      }
    },
    browser_action: {
      default_popup: "popup.html",
      default_area: "navbar",
    },
    permissions: ["activeTab"]
  },

  useAddonManager: "android-only",
};

add_task(async function setup() {
  await SpecialPowers.pushPrefEnv({
    "set": [
      ["extensions.openPopupWithoutUserGesture.enabled", true],
    ],
  });
});

async function testWithWindowState(state) {
  const background = async function(state) {
    const originalWindow = await browser.windows.getCurrent();

    let newWindowPromise;
    const tabLoadedPromise = new Promise(resolve => {
      browser.tabs.onUpdated.addListener(async (id, { status }, tab) => {
        if (tab.windowId === (await newWindowPromise).id && status === "complete") {
          resolve();
        }
      });
    });

    newWindowPromise = browser.windows.create({ url: "tab.html" });

    browser.test.onMessage.addListener(async (msg) => {
      if (msg === "close-window") {
        await browser.windows.remove((await newWindowPromise).id);
        browser.test.sendMessage("window-closed");
      }
    });

    tabLoadedPromise.then(async () => {
      const windowId = (await newWindowPromise).id;

      switch (state) {
        case "inactive":
          const focusChangePromise = new Promise(resolve => {
            browser.windows.onFocusChanged.addListener((focusedWindowId) => {
              if (focusedWindowId === originalWindow.id) {
                resolve();
              }
            })
          });
          await browser.windows.update(originalWindow.id, { focused: true });
          await focusChangePromise;
          break;
        case "minimized":
          await browser.windows.update(windowId, { state: "minimized" });
          break;
        default:
          throw new Error(`Invalid state: ${state}`);
      }

      await browser.browserAction.openPopup({ windowId });
    });
  };

  let extension = ExtensionTestUtils.loadExtension({
    ...extensionData,

    background: `(${background})(${JSON.stringify(state)})`,

    files: {
      "tab.html": "<!DOCTYPE html>",
      "popup.html": `<!DOCTYPE html><meta charset="utf-8"><script src="popup.js"><\/script>`,
      "popup.js"() {
        // Small timeout to ensure the popup doesn't immediately close, which can
        // happen when focus moves between windows
        // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
        setTimeout(async () => {
          let windows = await browser.windows.getAll();
          let highestWindowIdIsFocused = Math.max(...windows.map((w) => w.id))
            === windows.find((w) => w.focused).id;

          browser.test.assertEq(true, highestWindowIdIsFocused, "new window is focused");

          await browser.test.sendMessage("popup-open");

          // Bug 1800100: Window leaks if not explicitly closed
          window.close();
        }, 1000);
      },
    },
  });

  await extension.startup();
  await extension.awaitMessage("popup-open");
  await extension.sendMessage("close-window");
  await extension.awaitMessage("window-closed");
  await extension.unload();
}

add_task(async function test_browserAction_openPopup_window_inactive() {
  if (AppConstants.platform == "linux") {
    // TODO bug 1798334: Currently unreliable on linux
    todo(false, "Unreliable on linux");
    return;
  }
  await testWithWindowState("inactive");
});

add_task(async function test_browserAction_openPopup_window_minimized() {
  if (AppConstants.platform == "linux") {
    // TODO bug 1798334: Currently unreliable on linux
    todo(false, "Unreliable on linux");
    return;
  }
  await testWithWindowState("minimized");
});

add_task(async function test_browserAction_openPopup_invalid_window() {
  let extension = ExtensionTestUtils.loadExtension({
    ...extensionData,

    background: async function() {
      await browser.test.assertRejects(
        browser.browserAction.openPopup({ windowId: Number.MAX_SAFE_INTEGER }),
        /Invalid window ID/,
        "Should throw for invalid window ID"
      );
      browser.test.notifyPass("invalidWindow");
    },
  });

  await extension.startup();
  await extension.awaitFinish("invalidWindow");
  await extension.unload();
});
</script>

</body>
</html>
