const NOTIFY_CLOSED_OBJECTS_CHANGED = "sessionstore-closed-objects-changed";

add_setup(async () => {
  registerCleanupFunction(async () => {
    Services.obs.notifyObservers(null, "browser:purge-session-history");
  });
});

async function check_tab_close_notification(openedTab, expectNotification) {
  let tabUrl = openedTab.linkedBrowser.currentURI.spec;
  let win = openedTab.ownerGlobal;
  let initialTabCount = SessionStore.getClosedTabCountForWindow(win);

  let tabClosed = BrowserTestUtils.waitForTabClosing(openedTab);
  let notified = false;
  function topicObserver() {
    notified = true;
  }
  Services.obs.addObserver(topicObserver, NOTIFY_CLOSED_OBJECTS_CHANGED);

  BrowserTestUtils.removeTab(openedTab);
  await tabClosed;
  // SessionStore does a setTimeout(notify, 0) to notifyObservers when it handles TabClose
  // We need to wait long enough to be confident the observer would have been notified
  // if it was going to be.
  let ticks = 0;
  await TestUtils.waitForCondition(() => {
    return ++ticks > 1;
  });

  Services.obs.removeObserver(topicObserver, NOTIFY_CLOSED_OBJECTS_CHANGED);
  if (expectNotification) {
    Assert.ok(
      notified,
      `Expected ${NOTIFY_CLOSED_OBJECTS_CHANGED} when the ${tabUrl} tab closed`
    );
    Assert.equal(
      SessionStore.getClosedTabCountForWindow(win),
      initialTabCount + 1,
      "Expected closed tab count to have incremented"
    );
  } else {
    Assert.ok(
      !notified,
      `Expected no ${NOTIFY_CLOSED_OBJECTS_CHANGED} when the ${tabUrl} tab closed`
    );
    Assert.equal(
      SessionStore.getClosedTabCountForWindow(win),
      initialTabCount,
      "Expected closed tab count to have not changed"
    );
  }
}

add_task(async function test_control_case() {
  let win = window;
  let tabOpenedAndSwitchedTo = BrowserTestUtils.switchTab(
    win.gBrowser,
    () => {}
  );
  let tab = await BrowserTestUtils.openNewForegroundTab(
    win.gBrowser,
    "https://example.com/"
  );
  await tabOpenedAndSwitchedTo;
  await check_tab_close_notification(tab, true);
});

add_task(async function test_about_new_tab() {
  let win = window;
  let tabOpenedAndSwitchedTo = BrowserTestUtils.switchTab(
    win.gBrowser,
    () => {}
  );
  // This opens about:newtab:
  win.BrowserCommands.openTab();
  let tab = await tabOpenedAndSwitchedTo;
  await check_tab_close_notification(tab, false);
});

add_task(async function test_about_home() {
  let win = window;
  let tabOpenedAndSwitchedTo = BrowserTestUtils.switchTab(
    win.gBrowser,
    () => {}
  );
  let tab = await BrowserTestUtils.openNewForegroundTab(
    win.gBrowser,
    "about:home"
  );
  await tabOpenedAndSwitchedTo;
  await check_tab_close_notification(tab, false);
});

add_task(async function test_navigated_about_home() {
  let win = window;
  let tabOpenedAndSwitchedTo = BrowserTestUtils.switchTab(
    win.gBrowser,
    () => {}
  );
  let tab = await BrowserTestUtils.openNewForegroundTab(
    win.gBrowser,
    "https://example.com/"
  );
  await tabOpenedAndSwitchedTo;
  BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, "about:home");
  await BrowserTestUtils.browserLoaded(tab.linkedBrowser);
  // even if we end up on an ignorable URL,
  // if there's meaningful history, we should save this tab
  await check_tab_close_notification(tab, true);
});

add_task(async function test_about_blank() {
  let win = window;
  let tabOpenedAndSwitchedTo = BrowserTestUtils.switchTab(
    win.gBrowser,
    () => {}
  );
  let tab = await BrowserTestUtils.openNewForegroundTab(
    win.gBrowser,
    "about:blank"
  );
  await tabOpenedAndSwitchedTo;
  await check_tab_close_notification(tab, false);
});

add_task(async function test_about_privatebrowsing() {
  let win = window;
  let tabOpenedAndSwitchedTo = BrowserTestUtils.switchTab(
    win.gBrowser,
    () => {}
  );
  let tab = await BrowserTestUtils.openNewForegroundTab(
    win.gBrowser,
    "about:privatebrowsing"
  );
  await tabOpenedAndSwitchedTo;
  await check_tab_close_notification(tab, false);
});
