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

"use strict";

const { SafariProfileMigrator } = ChromeUtils.importESModule(
  "resource:///modules/SafariProfileMigrator.sys.mjs"
);

/**
 * Tests that if we don't have permission to read the contents
 * of ~/Library/Safari, that we can ask for permission to do that.
 *
 * This involves presenting the user with some instructions, and then
 * showing a native folder picker for the user to select the
 * ~/Library/Safari folder. This seems to give us read access to the
 * folder contents.
 *
 * Revoking permissions for reading the ~/Library/Safari folder is
 * not something that we know how to do just yet. It seems to be
 * something involving macOS's System Integrity Protection. This test
 * mocks out and simulates the actual permissions mechanism to make
 * this test run reliably and repeatably.
 */
add_task(async function test_safari_permissions() {
  let sandbox = sinon.createSandbox();
  registerCleanupFunction(() => {
    sandbox.restore();
  });

  let safariMigrator = new SafariProfileMigrator();
  sandbox.stub(MigrationUtils, "getMigrator").resolves(safariMigrator);

  sandbox
    .stub(SafariProfileMigrator.prototype, "hasPermissions")
    .onFirstCall()
    .resolves(false)
    .onSecondCall()
    .resolves(true);

  sandbox
    .stub(SafariProfileMigrator.prototype, "getPermissions")
    .resolves(true);

  sandbox
    .stub(SafariProfileMigrator.prototype, "getResources")
    .callsFake(() => {
      return Promise.resolve([
        {
          type: MigrationUtils.resourceTypes.BOOKMARKS,
          migrate: () => {},
        },
      ]);
    });

  let didMigration = new Promise(resolve => {
    sandbox
      .stub(SafariProfileMigrator.prototype, "migrate")
      .callsFake((aResourceTypes, aStartup, aProfile, aProgressCallback) => {
        Assert.ok(
          !aStartup,
          "Migrator should not have been called as a startup migration."
        );

        aProgressCallback(MigrationUtils.resourceTypes.BOOKMARKS);
        Services.obs.notifyObservers(null, "Migration:Ended");
        resolve();
      });
  });

  await withMigrationWizardDialog(async prefsWin => {
    let dialogBody = prefsWin.document.body;
    let wizard = dialogBody.querySelector("migration-wizard");
    let wizardDone = BrowserTestUtils.waitForEvent(
      wizard,
      "MigrationWizard:DoneMigration"
    );

    let shadow = wizard.openOrClosedShadowRoot;

    info("Choosing Safari");
    let panelItem = wizard.querySelector(
      `panel-item[key="${SafariProfileMigrator.key}"]`
    );
    panelItem.click();

    // Let's just choose "Bookmarks" for now.
    let resourceTypeList = shadow.querySelector("#resource-type-list");
    let resourceNodes = resourceTypeList.querySelectorAll(
      `label[data-resource-type]`
    );
    for (let resourceNode of resourceNodes) {
      resourceNode.control.checked =
        resourceNode.dataset.resourceType ==
        MigrationWizardConstants.DISPLAYED_RESOURCE_TYPES.BOOKMARKS;
    }

    let deck = shadow.querySelector("#wizard-deck");
    let switchedToSafariPermissionPage =
      BrowserTestUtils.waitForMutationCondition(
        deck,
        { attributeFilter: ["selected-view"] },
        () => {
          return (
            deck.getAttribute("selected-view") ==
            "page-" + MigrationWizardConstants.PAGES.SAFARI_PERMISSION
          );
        }
      );

    let importButton = shadow.querySelector("#import");
    importButton.click();
    await switchedToSafariPermissionPage;
    Assert.ok(true, "Went to Safari permission page after attempting import.");

    let requestPermissions = shadow.querySelector(
      "#safari-request-permissions"
    );
    requestPermissions.click();
    await didMigration;
    Assert.ok(true, "Completed migration");

    let dialog = prefsWin.document.querySelector("#migrationWizardDialog");
    let doneButton = shadow.querySelector(
      "div[name='page-progress'] .done-button"
    );
    let dialogClosed = BrowserTestUtils.waitForEvent(dialog, "close");

    doneButton.click();
    await dialogClosed;
    await wizardDone;
  });
});
