"use strict";

const PATH = "browser/browser/components/sessionstore/test/empty.html";
var URLS_WIN1 = [
  "https://example.com/" + PATH,
  "https://example.org/" + PATH,
  "http://test1.mochi.test:8888/" + PATH,
  "http://test1.example.com/" + PATH,
];
var EXPECTED_URLS_WIN1 = ["about:blank", ...URLS_WIN1];

var URLS_WIN2 = [
  "http://sub1.test1.mochi.test:8888/" + PATH,
  "http://sub2.xn--lt-uia.mochi.test:8888/" + PATH,
  "http://test2.mochi.test:8888/" + PATH,
  "http://sub1.test2.example.org/" + PATH,
  "http://sub2.test1.example.org/" + PATH,
  "http://test2.example.com/" + PATH,
];
var EXPECTED_URLS_WIN2 = ["about:blank", ...URLS_WIN2];

requestLongerTimeout(4);

function allTabsRestored(win, expectedUrls) {
  return new Promise(resolve => {
    let tabsRestored = 0;
    function handler(event) {
      let spec = event.target.linkedBrowser.currentURI.spec;
      if (expectedUrls.includes(spec)) {
        tabsRestored++;
      }
      info(`Got SSTabRestored for ${spec}, tabsRestored=${tabsRestored}`);
      if (tabsRestored === expectedUrls.length) {
        win.gBrowser.tabContainer.removeEventListener(
          "SSTabRestored",
          handler,
          true
        );
        resolve();
      }
    }
    win.gBrowser.tabContainer.addEventListener("SSTabRestored", handler, true);
  });
}

async function windowAndTabsRestored(win, expectedUrls) {
  await TestUtils.topicObserved(
    "browser-window-before-show",
    subject => subject === win
  );
  return allTabsRestored(win, expectedUrls);
}

add_task(async () => {
  await SpecialPowers.pushPrefEnv({
    set: [
      // Set the pref to true so we know exactly how many tabs should be restoring at
      // any given time. This guarantees that a finishing load won't start another.
      ["browser.sessionstore.restore_on_demand", false],
    ],
  });

  forgetClosedWindows();
  is(SessionStore.getClosedWindowCount(), 0, "starting with no closed windows");

  // Open window 1, with different tabs
  let win1 = await BrowserTestUtils.openNewBrowserWindow();
  for (let url of URLS_WIN1) {
    await BrowserTestUtils.openNewForegroundTab(win1.gBrowser, url);
  }

  // Open window 2, with different tabs
  let win2 = await BrowserTestUtils.openNewBrowserWindow();
  for (let url of URLS_WIN2) {
    await BrowserTestUtils.openNewForegroundTab(win2.gBrowser, url);
  }

  await TabStateFlusher.flushWindow(win1);
  await TabStateFlusher.flushWindow(win2);

  // Close both windows
  await BrowserTestUtils.closeWindow(win1);
  await BrowserTestUtils.closeWindow(win2);
  await forceSaveState();

  // Verify both windows were accounted for by session store
  is(
    ss.getClosedWindowCount(),
    2,
    "The closed windows was added to Recently Closed Windows"
  );

  // We previously used to manually navigate the Library menu to click the
  // "Reopen all Windows" button, but that reopens all windows at once without
  // returning a reference to each window. Since we need to attach listeners to
  // these windows *before* they start restoring tabs, we now manually call
  // undoCloseWindow() here, which has the same effect, but also gives us the
  // window references.
  info("Reopening windows");
  let restoredWindows = [];
  while (SessionStore.getClosedWindowCount() > 0) {
    restoredWindows.unshift(undoCloseWindow());
  }
  is(restoredWindows.length, 2, "Reopened correct number of windows");

  let win1Restored = windowAndTabsRestored(
    restoredWindows[0],
    EXPECTED_URLS_WIN1
  );
  let win2Restored = windowAndTabsRestored(
    restoredWindows[1],
    EXPECTED_URLS_WIN2
  );

  info("About to wait for tabs to be restored");
  await Promise.all([win1Restored, win2Restored]);

  is(
    restoredWindows[0].gBrowser.tabs.length,
    EXPECTED_URLS_WIN1.length,
    "All tabs restored"
  );
  is(
    restoredWindows[1].gBrowser.tabs.length,
    EXPECTED_URLS_WIN2.length,
    "All tabs restored"
  );

  // Verify that tabs opened as expected
  Assert.deepEqual(
    restoredWindows[0].gBrowser.tabs.map(
      tab => tab.linkedBrowser.currentURI.spec
    ),
    EXPECTED_URLS_WIN1
  );
  Assert.deepEqual(
    restoredWindows[1].gBrowser.tabs.map(
      tab => tab.linkedBrowser.currentURI.spec
    ),
    EXPECTED_URLS_WIN2
  );

  info("About to close windows");
  await BrowserTestUtils.closeWindow(restoredWindows[0]);
  await BrowserTestUtils.closeWindow(restoredWindows[1]);
});
