const TEST_ORIGIN = "https://example.org";
const ABOUT_LOGINS_ORIGIN = "about:logins";
const TEST_URL_PATH = `${TEST_ORIGIN}${DIRECTORY_PATH}form_basic_login.html`;

const LOGINS_DATA = [
  {
    origin: "https://aurl.com",
    username: "user1",
    password: "pass1",
    guid: Services.uuid.generateUUID().toString(),
  },
  {
    origin: TEST_ORIGIN,
    username: "user2",
    password: "pass2",
    guid: Services.uuid.generateUUID().toString(),
  },
  {
    origin: TEST_ORIGIN,
    username: "user3",
    password: "pass3",
    guid: Services.uuid.generateUUID().toString(),
  },
];

const waitForAppMenu = async () => {
  const appMenu = document.getElementById("appMenu-popup");
  const appMenuButton = document.getElementById("PanelUI-menu-button");
  await TestUtils.waitForCondition(
    () => BrowserTestUtils.isVisible(appMenuButton),
    "App menu button should be visible."
  );

  let popupshown = BrowserTestUtils.waitForEvent(appMenu, "popupshown");
  EventUtils.synthesizeMouseAtCenter(appMenuButton, {});
  await popupshown;
  Assert.equal(
    appMenu.state,
    "open",
    `Menu panel (${appMenu.id}) should be visible`
  );
};

const isExpectedLoginItemSelected = async ({ expectedGuid }) => {
  const loginList = content.document.querySelector("login-list").shadowRoot;

  await ContentTaskUtils.waitForCondition(
    () =>
      loginList.querySelector("login-list-item[aria-selected='true']")?.dataset
        ?.guid === expectedGuid,
    "Wait for login item to be selected"
  );

  Assert.equal(
    loginList.querySelector("login-list-item[aria-selected='true']")?.dataset
      ?.guid,
    expectedGuid,
    "Expected login is preselected"
  );
};

add_setup(async () => {
  await SpecialPowers.pushPrefEnv({
    set: [["test.wait300msAfterTabSwitch", true]],
  });

  await Services.logins.addLogins(
    LOGINS_DATA.map(login => LoginTestUtils.testData.formLogin(login))
  );
});

add_task(async function test_about_logins_defaults_to_first_item() {
  await BrowserTestUtils.withNewTab(
    {
      gBrowser,
      url: "about:logins#random-guid",
    },
    async function (gBrowser) {
      await SpecialPowers.spawn(
        gBrowser,
        [{ expectedGuid: LOGINS_DATA[0].guid }],
        isExpectedLoginItemSelected
      );

      Assert.ok(
        true,
        "First item of the list is selected when random hash is supplied."
      );
    }
  );
});

add_task(
  async function test_gear_icon_opens_about_logins_with_preselected_login() {
    await BrowserTestUtils.withNewTab(
      {
        gBrowser,
        url: TEST_URL_PATH,
      },
      async function (browser) {
        const popup = document.getElementById("PopupAutoComplete");

        await openACPopup(popup, browser, "#form-basic-username");

        const secondLoginItem = popup.firstChild.getItemAtIndex(1);
        const secondLoginItemSecondaryAction = secondLoginItem.querySelector(
          ".ac-secondary-action"
        );

        Assert.ok(
          !secondLoginItemSecondaryAction.checkVisibility({
            checkVisibilityCSS: true,
          }),
          "Secondary action should not be visible initially"
        );

        await EventUtils.synthesizeKey("KEY_ArrowDown");
        await EventUtils.synthesizeKey("KEY_ArrowDown");

        await BrowserTestUtils.waitForCondition(
          () => secondLoginItem.attributes.selected,
          "Wait for second login to become active"
        );

        Assert.ok(
          secondLoginItemSecondaryAction.checkVisibility({
            checkVisibilityCSS: true,
          }),
          "Secondary action should be visible when item is active"
        );

        const aboutLoginsTabPromise = BrowserTestUtils.waitForNewTab(
          gBrowser,
          url => url.includes(ABOUT_LOGINS_ORIGIN),
          true
        );

        EventUtils.synthesizeMouseAtCenter(secondLoginItemSecondaryAction, {});
        const aboutLoginsTab = await aboutLoginsTabPromise;

        await SpecialPowers.spawn(
          aboutLoginsTab.linkedBrowser,
          [{ expectedGuid: LOGINS_DATA[2].guid }],
          isExpectedLoginItemSelected
        );

        await closePopup(popup);
        gBrowser.removeTab(aboutLoginsTab);
      }
    );
  }
);

add_task(
  async function test_password_menu_opens_about_logins_with_preselected_login() {
    await BrowserTestUtils.withNewTab(
      {
        gBrowser,
        url: TEST_URL_PATH,
      },
      async function (_browser) {
        await waitForAppMenu();

        const appMenuPasswordsButton = document.getElementById(
          "appMenu-passwords-button"
        );

        const aboutLoginsTabPromise = BrowserTestUtils.waitForNewTab(
          gBrowser,
          url => url.includes(ABOUT_LOGINS_ORIGIN),
          true
        );

        EventUtils.synthesizeMouseAtCenter(appMenuPasswordsButton, {});

        const aboutLoginsTab = await aboutLoginsTabPromise;

        await SpecialPowers.spawn(
          aboutLoginsTab.linkedBrowser,
          [{ expectedGuid: LOGINS_DATA[1].guid }],
          isExpectedLoginItemSelected
        );

        gBrowser.removeTab(aboutLoginsTab);
      }
    );
  }
);

add_task(async function test_new_login_url_has_correct_hash() {
  await BrowserTestUtils.withNewTab(
    {
      gBrowser,
      url: "about:logins",
    },
    async function (gBrowser) {
      await SpecialPowers.spawn(gBrowser, [], async () => {
        const loginList =
          content.document.querySelector("login-list").shadowRoot;
        const createLoginButton = loginList
          .querySelector("create-login-button")
          .shadowRoot.querySelector("button");

        createLoginButton.click();

        await ContentTaskUtils.waitForCondition(
          () =>
            ContentTaskUtils.isVisible(
              loginList.querySelector("#new-login-list-item")
            ),
          "Wait for new login-list-item to become visible"
        );

        Assert.equal(
          content.location.hash,
          "",
          "Location hash should be empty"
        );
      });
    }
  );
});

add_task(async function test_no_logins_empty_url_hash() {
  Services.logins.removeAllUserFacingLogins();
  await BrowserTestUtils.withNewTab(
    {
      gBrowser,
      url: TEST_URL_PATH,
    },
    async function () {
      await waitForAppMenu();

      const appMenuPasswordsButton = document.getElementById(
        "appMenu-passwords-button"
      );

      const aboutLoginsTabPromise = BrowserTestUtils.waitForNewTab(
        gBrowser,
        url => new URL(url).hash === "",
        true
      );

      EventUtils.synthesizeMouseAtCenter(appMenuPasswordsButton, {});

      const aboutLoginsTab = await aboutLoginsTabPromise;

      gBrowser.removeTab(aboutLoginsTab);
    }
  );
});
