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

const kDefaultEngineName = "engine1";
const kOtherAppProvidedEngineId = "engine2";

add_setup(async function () {
  useHttpServer();
  SearchTestUtils.setRemoteSettingsConfig([
    { identifier: kDefaultEngineName },
    { identifier: kOtherAppProvidedEngineId },
  ]);
  Assert.ok(!Services.search.isInitialized);
  Services.prefs.setBoolPref(
    "browser.search.removeEngineInfobar.enabled",
    false
  );
});

add_task(async function test_defaultEngine() {
  await Services.search.init();
  await SearchTestUtils.installOpenSearchEngine({
    url: `${gHttpURL}/opensearch/generic1.xml`,
  });

  Assert.equal(Services.search.defaultEngine.name, kDefaultEngineName);
});

// Setting the search engine should be persisted across restarts.
add_task(async function test_persistAcrossRestarts() {
  // Set the engine through the API.
  await Services.search.setDefault(
    Services.search.getEngineByName(kTestEngineName),
    Ci.nsISearchService.CHANGE_REASON_UNKNOWN
  );
  Assert.equal(Services.search.defaultEngine.name, kTestEngineName);
  await promiseAfterSettings();

  // Check that the a hash was saved.
  let metadata = await promiseGlobalMetadata();
  Assert.equal(metadata.defaultEngineIdHash.length, 44);

  // Re-init and check the engine is still the same.
  Services.search.wrappedJSObject.reset();
  await Services.search.init(true);
  Assert.equal(Services.search.defaultEngine.name, kTestEngineName);

  // Cleanup (set the engine back to default).
  Services.search.resetToAppDefaultEngine();
  Assert.equal(Services.search.defaultEngine.name, kDefaultEngineName);
});

// An engine set without a valid hash should be ignored.
add_task(async function test_ignoreInvalidHash() {
  // Set the engine through the API.
  await Services.search.setDefault(
    Services.search.getEngineByName(kTestEngineName),
    Ci.nsISearchService.CHANGE_REASON_UNKNOWN
  );
  Assert.equal(Services.search.defaultEngine.name, kTestEngineName);
  await promiseAfterSettings();

  // Then mess with the file (make the hash invalid).
  let metadata = await promiseGlobalMetadata();
  metadata.defaultEngineIdHash = "invalid";
  await promiseSaveGlobalMetadata(metadata);

  // Re-init the search service, and check that the json file is ignored.
  Services.search.wrappedJSObject.reset();
  await Services.search.init(true);
  Assert.equal(Services.search.defaultEngine.name, kDefaultEngineName);
});

// Resetting the engine to the default should remove the saved value.
add_task(async function test_settingToDefault() {
  // Set the engine through the API.
  await Services.search.setDefault(
    Services.search.getEngineByName(kTestEngineName),
    Ci.nsISearchService.CHANGE_REASON_UNKNOWN
  );
  Assert.equal(Services.search.defaultEngine.name, kTestEngineName);
  await promiseAfterSettings();

  // Check that the current engine was saved.
  let metadata = await promiseGlobalMetadata();
  let currentEngine = Services.search.getEngineByName(kTestEngineName);
  Assert.equal(metadata.defaultEngineId, currentEngine.id);

  // Then set the engine back to the default through the API.
  await Services.search.setDefault(
    Services.search.getEngineByName(kDefaultEngineName),
    Ci.nsISearchService.CHANGE_REASON_UNKNOWN
  );
  await promiseAfterSettings();

  // Check that the current engine is no longer saved in the JSON file.
  metadata = await promiseGlobalMetadata();
  Assert.equal(metadata.defaultEngineId, "");
});

add_task(async function test_resetToOriginalDefaultEngine() {
  Assert.equal(Services.search.defaultEngine.name, kDefaultEngineName);

  await Services.search.setDefault(
    Services.search.getEngineByName(kTestEngineName),
    Ci.nsISearchService.CHANGE_REASON_UNKNOWN
  );
  Assert.equal(Services.search.defaultEngine.name, kTestEngineName);
  await promiseAfterSettings();

  Services.search.resetToAppDefaultEngine();
  Assert.equal(Services.search.defaultEngine.name, kDefaultEngineName);
  await promiseAfterSettings();
});

add_task(async function test_fallback_kept_after_restart() {
  // Set current engine to a default engine that isn't the original default.
  let otherAppProvidedEngine = Services.search.getEngineById(
    kOtherAppProvidedEngineId
  );

  await Services.search.setDefault(
    otherAppProvidedEngine,
    Ci.nsISearchService.CHANGE_REASON_UNKNOWN
  );
  Assert.equal(Services.search.defaultEngine.name, otherAppProvidedEngine.name);
  await promiseAfterSettings();

  // Remove that engine...
  await Services.search.removeEngine(otherAppProvidedEngine);
  // The engine being a default (built-in) one, it should be hidden
  // rather than actually removed.
  Assert.ok(otherAppProvidedEngine.hidden);

  // Using the defaultEngine getter should force a fallback to the
  // original default engine.
  Assert.equal(Services.search.defaultEngine.name, kDefaultEngineName);

  // Restoring the default engines should unhide our built-in test
  // engine, but not change the value of defaultEngine.
  Services.search.restoreDefaultEngines();
  Assert.ok(!otherAppProvidedEngine.hidden);
  Assert.equal(Services.search.defaultEngine.name, kDefaultEngineName);
  await promiseAfterSettings();

  // After a restart, the defaultEngine value should still be unchanged.
  Services.search.wrappedJSObject.reset();
  await Services.search.init(true);
  Assert.equal(Services.search.defaultEngine.name, kDefaultEngineName);
});
