/* Any copyright is dedicated to the Public Domain.
   http://creativecommons.org/publicdomain/zero/1.0/ */

"use strict";

const { SyncDisconnect, SyncDisconnectInternal } = ChromeUtils.importESModule(
  "resource://services-sync/SyncDisconnect.sys.mjs"
);
const { AsyncShutdown } = ChromeUtils.importESModule(
  "resource://gre/modules/AsyncShutdown.sys.mjs"
);
const { PREF_LAST_FXA_USER } = ChromeUtils.importESModule(
  "resource://gre/modules/FxAccountsCommon.sys.mjs"
);

add_task(async function test_shutdown_blocker() {
  let spySignout = sinon.stub(
    SyncDisconnectInternal,
    "doSyncAndAccountDisconnect"
  );

  // We don't need to check for the lock regularly as we end up aborting the wait.
  SyncDisconnectInternal.lockRetryInterval = 1000;
  // Force the retry count to a very large value - this test should never
  // abort due to the retry count and we want the test to fail (aka timeout)
  // should our abort code not work.
  SyncDisconnectInternal.lockRetryCount = 10000;
  // mock the "browser" sanitize function - it should not be called by
  // this test.
  let spyBrowser = sinon.stub(SyncDisconnectInternal, "doSanitizeBrowserData");
  // mock Sync
  let mockEngine1 = {
    enabled: true,
    name: "Test Engine 1",
    wipeClient: sinon.spy(),
  };
  let mockEngine2 = {
    enabled: false,
    name: "Test Engine 2",
    wipeClient: sinon.spy(),
  };

  // This weave mock never gives up the lock.
  let Weave = {
    Service: {
      enabled: true,
      lock: () => false, // so we never get the lock.
      unlock: sinon.spy(),

      engineManager: {
        getAll: sinon.stub().returns([mockEngine1, mockEngine2]),
      },
      errorHandler: {
        resetFileLog: sinon.spy(),
      },
    },
  };
  let weaveStub = sinon.stub(SyncDisconnectInternal, "getWeave");
  weaveStub.returns(Weave);

  Services.prefs.setStringPref(PREF_LAST_FXA_USER, "dGVzdEBleGFtcGxlLmNvbQ==");

  let promiseDisconnected = SyncDisconnect.disconnect(true);

  // Pretend we hit the shutdown blocker.
  info("simulating quitApplicationGranted");
  Services.prefs.setBoolPref("toolkit.asyncshutdown.testing", true);
  AsyncShutdown.quitApplicationGranted._trigger();
  Services.prefs.clearUserPref("toolkit.asyncshutdown.testing");

  info("waiting for disconnect to complete");
  await promiseDisconnected;

  Assert.ok(
    !Services.prefs.prefHasUserValue(PREF_LAST_FXA_USER),
    "Should have reset different user warning pref"
  );
  Assert.equal(
    Weave.Service.unlock.callCount,
    0,
    "should not have unlocked at the end"
  );
  Assert.ok(!Weave.Service.enabled, "Weave should be and remain disabled");
  Assert.equal(
    Weave.Service.errorHandler.resetFileLog.callCount,
    1,
    "should have reset the log"
  );
  Assert.equal(
    mockEngine1.wipeClient.callCount,
    1,
    "enabled engine should have been wiped"
  );
  Assert.equal(
    mockEngine2.wipeClient.callCount,
    0,
    "disabled engine should not have been wiped"
  );
  Assert.equal(spyBrowser.callCount, 1, "should not sanitize the browser");
  Assert.equal(spySignout.callCount, 1, "should have signed out of FxA");
});
