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

"use strict";

const ABOUT_URL = "about:webauthn";

var doc, tab;

async function send_authinfo_and_open_pin_section(ops) {
  reset_about_page(doc);
  send_auth_info_and_check_categories(doc, ops);

  ["credentials-tab-button", "bio-enrollments-tab-button"].forEach(
    button_id => {
      let button = doc.getElementById(button_id);
      is(
        button.style.display,
        "none",
        button_id + " in the sidebar not hidden"
      );
    }
  );

  if (ops.clientPin !== null) {
    let pin_tab_button = doc.getElementById("pin-tab-button");
    // Check if PIN section is visible
    isnot(
      pin_tab_button.style.display,
      "none",
      "PIN button in the sidebar not visible"
    );

    // Click the section and wait for it to open
    let pin_section = doc.getElementById("set-change-pin-section");
    pin_tab_button.click();
    isnot(pin_section.style.display, "none", "PIN section not visible");
    is(
      pin_tab_button.getAttribute("selected"),
      "true",
      "PIN section button not selected"
    );
  }
}

add_setup(async function () {
  info("Starting about:webauthn");
  tab = await BrowserTestUtils.openNewForegroundTab({
    gBrowser,
    opening: "about:webauthn",
    waitForLoad: true,
  });

  doc = tab.linkedBrowser.contentDocument;
});

registerCleanupFunction(async function () {
  // Close tab.
  await BrowserTestUtils.removeTab(tab);
});

add_task(async function pin_not_supported() {
  // Not setting clientPIN at all should lead to not showing it in the sidebar
  send_authinfo_and_open_pin_section({ uv: true, clientPin: null });
  // Check if PIN section is invisible
  let pin_tab_button = doc.getElementById("pin-tab-button");
  is(pin_tab_button.style.display, "none", "PIN button in the sidebar visible");
});

add_task(async function pin_already_set() {
  send_authinfo_and_open_pin_section({ clientPin: true });

  let set_pin_button = doc.getElementById("set-pin-button");
  is(set_pin_button.style.display, "none", "Set PIN button visible");

  let change_pin_button = doc.getElementById("change-pin-button");
  isnot(
    change_pin_button.style.display,
    "none",
    "Change PIN button not visible"
  );

  let current_pin_div = doc.getElementById("current-pin-div");
  is(current_pin_div.hidden, false, "Current PIN field not visible");

  // Test that the button is only active if both inputs are set the same
  let new_pin = doc.getElementById("new-pin");
  let new_pin_repeat = doc.getElementById("new-pin-repeat");
  let current_pin = doc.getElementById("current-pin");

  set_text(new_pin, "abcdefg");
  is(change_pin_button.disabled, true, "Change PIN button not disabled");
  set_text(new_pin_repeat, "abcde");
  is(change_pin_button.disabled, true, "Change PIN button not disabled");
  set_text(new_pin_repeat, "abcdefg");
  is(change_pin_button.disabled, true, "Change PIN button not disabled");
  set_text(current_pin, "1234567");
  is(change_pin_button.disabled, false, "Change PIN button disabled");
});

add_task(async function pin_not_yet_set() {
  send_authinfo_and_open_pin_section({ clientPin: false });

  let set_pin_button = doc.getElementById("set-pin-button");
  isnot(set_pin_button.style.display, "none", "Set PIN button not visible");

  let change_pin_button = doc.getElementById("change-pin-button");
  is(change_pin_button.style.display, "none", "Change PIN button visible");

  let current_pin_div = doc.getElementById("current-pin-div");
  is(current_pin_div.hidden, true, "Current PIN field visible");

  // Test that the button is only active if both inputs are set the same
  let new_pin = doc.getElementById("new-pin");
  let new_pin_repeat = doc.getElementById("new-pin-repeat");

  set_text(new_pin, "abcdefg");
  is(set_pin_button.disabled, true, "Set PIN button not disabled");
  set_text(new_pin_repeat, "abcde");
  is(set_pin_button.disabled, true, "Set PIN button not disabled");
  set_text(new_pin_repeat, "abcdefg");
  is(set_pin_button.disabled, false, "Set PIN button disabled");
});

add_task(async function pin_switch_back_and_forth() {
  // This will click the PIN section button
  send_authinfo_and_open_pin_section({ clientPin: false });

  let pin_tab_button = doc.getElementById("pin-tab-button");
  let pin_section = doc.getElementById("set-change-pin-section");
  let info_tab_button = doc.getElementById("info-tab-button");
  let info_section = doc.getElementById("token-info-section");

  // a11y-tree is racy here, so we have to wait a tick for it to get up to date
  await TestUtils.waitForTick();
  // Now click the "info"-button and verify the correct buttons are highlighted
  info_tab_button.click();
  // await info_promise;
  isnot(info_section.style.display, "none", "info section not visible");
  is(
    info_tab_button.getAttribute("selected"),
    "true",
    "Info tab button not selected"
  );
  isnot(
    pin_tab_button.getAttribute("selected"),
    "true",
    "PIN tab button selected"
  );

  // Click back to the PIN section
  pin_tab_button.click();
  isnot(pin_section.style.display, "none", "PIN section not visible");
  is(
    pin_tab_button.getAttribute("selected"),
    "true",
    "PIN tab button not selected"
  );
  isnot(
    info_tab_button.getAttribute("selected"),
    "true",
    "Info button selected"
  );
});

add_task(async function invalid_pin() {
  send_authinfo_and_open_pin_section({ clientPin: true });
  let pin_tab_button = doc.getElementById("pin-tab-button");
  // Click the section and wait for it to open
  pin_tab_button.click();
  is(
    pin_tab_button.getAttribute("selected"),
    "true",
    "PIN section button not selected"
  );

  let change_pin_button = doc.getElementById("change-pin-button");

  // Test that the button is only active if both inputs are set the same
  let new_pin = doc.getElementById("new-pin");
  let new_pin_repeat = doc.getElementById("new-pin-repeat");
  let current_pin = doc.getElementById("current-pin");

  // Needed to activate change_pin_button
  set_text(new_pin, "abcdefg");
  set_text(new_pin_repeat, "abcdefg");
  set_text(current_pin, "1234567");

  // This should silently error out since we have no authenticator
  change_pin_button.click();

  // Now we fake a response from the authenticator, saying the PIN was invalid
  let pin_required = doc.getElementById("pin-required-section");
  let msg = JSON.stringify({ type: "pin-required" });
  Services.obs.notifyObservers(null, "about-webauthn-prompt", msg);
  isnot(pin_required.style.display, "none", "PIN required dialog not visible");

  let info_tab_button = doc.getElementById("info-tab-button");
  is(
    info_tab_button.classList.contains("disabled-category"),
    true,
    "Sidebar not disabled"
  );

  let pin_field = doc.getElementById("pin-required");
  let send_pin_button = doc.getElementById("send-pin-button");

  set_text(pin_field, "654321");
  send_pin_button.click();

  is(
    pin_required.style.display,
    "none",
    "PIN required dialog did not disappear"
  );
  let pin_section = doc.getElementById("set-change-pin-section");
  isnot(pin_section.style.display, "none", "PIN section did not reappear");
});
