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

"use strict";

var doc, tab;

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);
});

function send_bio_enrollment_command(state) {
  let msg = JSON.stringify({
    type: "bio-enrollment-update",
    result: state,
  });
  Services.obs.notifyObservers(null, "about-webauthn-prompt", msg);
}

function check_bio_buttons_disabled(disabled) {
  let buttons = Array.from(doc.getElementsByClassName("bio-enrollment-button"));
  buttons.forEach(button => {
    is(button.disabled, disabled);
  });
  return buttons;
}

function check_tab_buttons_aria(button_id) {
  let button = doc.getElementById(button_id);
  is(button.role, "tab", button_id + " in the sidebar is a tab");
  ok(
    button.hasAttribute("aria-controls"),
    button_id + " in the sidebar is a tab with an assigned tablist"
  );
  ok(
    button.hasAttribute("aria-selected"),
    button_id + " in the sidebar is a tab that can be or is selected"
  );
  ok(
    button.hasAttribute("tabindex"),
    button_id + " in the sidebar is a tab with keyboard focusability provided"
  );
}

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

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

  if (ops.bioEnroll !== null || ops.userVerificationMgmtPreview !== null) {
    let bio_enrollments_tab_button = doc.getElementById(
      "bio-enrollments-tab-button"
    );
    // Check if bio enrollment section is visible
    isnot(
      bio_enrollments_tab_button.style.display,
      "none",
      "bio enrollment button in the sidebar not visible"
    );
    check_tab_buttons_aria("bio-enrollments-tab-button");

    // Click the section and wait for it to open
    let bio_enrollment_section = doc.getElementById("bio-enrollment-section");
    bio_enrollments_tab_button.click();
    isnot(
      bio_enrollment_section.style.display,
      "none",
      "bio enrollment section not visible"
    );
    is(
      bio_enrollments_tab_button.getAttribute("selected"),
      "true",
      "bio enrollment section button not selected"
    );
  }
}

add_task(async function bio_enrollment_not_supported() {
  send_authinfo_and_open_bio_section({
    bioEnroll: null,
    userVerificationMgmtPreview: null,
  });
  let bio_enrollments_tab_button = doc.getElementById(
    "bio-enrollments-tab-button"
  );
  is(
    bio_enrollments_tab_button.style.display,
    "none",
    "bio enrollments button in the sidebar visible"
  );
});

add_task(async function bio_enrollment_supported() {
  // Setting bioEnroll should show the button in the sidebar
  // The function is checking this for us.
  send_authinfo_and_open_bio_section({
    bioEnroll: true,
    userVerificationMgmtPreview: null,
  });
  // Setting Preview should show the button in the sidebar
  send_authinfo_and_open_bio_section({
    bioEnroll: null,
    userVerificationMgmtPreview: true,
  });
  // Setting both should also work
  send_authinfo_and_open_bio_section({
    bioEnroll: true,
    userVerificationMgmtPreview: true,
  });
});

add_task(async function bio_enrollment_empty_list() {
  send_authinfo_and_open_bio_section({ bioEnroll: true });

  let list_bio_enrollments_button = doc.getElementById(
    "list-bio-enrollments-button"
  );
  let add_bio_enrollment_button = doc.getElementById(
    "add-bio-enrollment-button"
  );
  isnot(
    list_bio_enrollments_button.style.display,
    "none",
    "List bio enrollments button in the sidebar not visible"
  );
  isnot(
    add_bio_enrollment_button.style.display,
    "none",
    "Add bio enrollment button in the sidebar not visible"
  );

  // Bio list should initially not be visible
  let bio_enrollment_list = doc.getElementById(
    "bio-enrollment-list-subsection"
  );
  is(bio_enrollment_list.hidden, true, "bio enrollment list visible");

  list_bio_enrollments_button.click();
  is(
    list_bio_enrollments_button.disabled,
    true,
    "List bio enrollments button not disabled while op in progress"
  );
  is(
    add_bio_enrollment_button.disabled,
    true,
    "Add bio enrollment button not disabled while op in progress"
  );

  send_bio_enrollment_command({ EnrollmentList: [] });
  is(
    list_bio_enrollments_button.disabled,
    false,
    "List bio enrollments button disabled"
  );
  is(
    add_bio_enrollment_button.disabled,
    false,
    "Add bio enrollment button disabled"
  );

  is(bio_enrollment_list.hidden, false, "bio enrollments list visible");
  let bio_enrollment_list_empty_label = doc.getElementById(
    "bio-enrollment-list-empty-label"
  );
  is(
    bio_enrollment_list_empty_label.hidden,
    false,
    "bio enrollments list empty label not visible"
  );
});

add_task(async function bio_enrollment_real_data() {
  send_authinfo_and_open_bio_section({ bioEnroll: true });
  let list_bio_enrollments_button = doc.getElementById(
    "list-bio-enrollments-button"
  );
  let add_bio_enrollment_button = doc.getElementById(
    "add-bio-enrollment-button"
  );
  list_bio_enrollments_button.click();
  send_bio_enrollment_command({ EnrollmentList: REAL_DATA });
  is(
    list_bio_enrollments_button.disabled,
    false,
    "List bio enrollments button disabled"
  );
  is(
    add_bio_enrollment_button.disabled,
    false,
    "Add bio enrollment button disabled"
  );
  let bio_enrollment_list = doc.getElementById("bio-enrollment-list");
  is(
    bio_enrollment_list.rows.length,
    2,
    "bio enrollment list table doesn't contain 2 bio enrollments"
  );
  is(bio_enrollment_list.rows[0].cells[0].textContent, "right-middle");
  is(bio_enrollment_list.rows[1].cells[0].textContent, "right-index");
  let buttons = check_bio_buttons_disabled(false);
  // 2 for each bio + 1 for the list button + 1 for the add button + hidden "start enroll"
  is(buttons.length, 5);

  list_bio_enrollments_button.click();
  buttons = check_bio_buttons_disabled(true);
});

add_task(async function bio_enrollment_add_new() {
  send_authinfo_and_open_bio_section({ bioEnroll: true });
  let add_bio_enrollment_button = doc.getElementById(
    "add-bio-enrollment-button"
  );
  add_bio_enrollment_button.click();
  let add_bio_enrollment_section = doc.getElementById(
    "add-bio-enrollment-section"
  );
  isnot(
    add_bio_enrollment_section.style.display,
    "none",
    "Add bio enrollment section invisible"
  );
  let enrollment_name = doc.getElementById("enrollment-name");
  enrollment_name.value = "Test123";

  let start_enrollment_button = doc.getElementById("start-enrollment-button");
  start_enrollment_button.click();

  check_bio_buttons_disabled(true);
  send_bio_enrollment_command({
    SampleStatus: ["Ctap2EnrollFeedbackFpGood", 3],
  });

  let enrollment_update = doc.getElementById("enrollment-update");
  is(enrollment_update.children.length, 1);
  check_bio_buttons_disabled(true);

  send_bio_enrollment_command({
    SampleStatus: ["Ctap2EnrollFeedbackFpGood", 2],
  });
  send_bio_enrollment_command({
    SampleStatus: ["Ctap2EnrollFeedbackFpGood", 1],
  });
  send_bio_enrollment_command({
    SampleStatus: ["Ctap2EnrollFeedbackFpGood", 0],
  });
  is(enrollment_update.children.length, 4);
  check_bio_buttons_disabled(true);
  // We tell the about-page that we still have enrollments (bioEnroll: true).
  // So it will automatically request a refreshed list from the authenticator, disabling
  // all the buttons again.
  send_bio_enrollment_command({ AddSuccess: { options: { bioEnroll: true } } });
  is(enrollment_update.children.length, 0);
  is(enrollment_name.value, "", "Enrollment name field did not get cleared");
  check_bio_buttons_disabled(true);
});

add_task(async function bio_enrollment_delete() {
  send_authinfo_and_open_bio_section({ bioEnroll: true });
  let list_bio_enrollments_button = doc.getElementById(
    "list-bio-enrollments-button"
  );
  list_bio_enrollments_button.click();
  send_bio_enrollment_command({ EnrollmentList: REAL_DATA });
  let buttons = check_bio_buttons_disabled(false);
  buttons[1].click();
  check_bio_buttons_disabled(true);
  // Tell the about page, we still have enrollments
  send_bio_enrollment_command({
    DeleteSuccess: { options: { bioEnroll: true } },
  });
  // This will cause it to automatically request the new list, thus disabling all buttons
  check_bio_buttons_disabled(true);
  send_bio_enrollment_command({ EnrollmentList: REAL_DATA });
  buttons = check_bio_buttons_disabled(false);
  buttons[1].click();

  // Confirmation dialog should pop open
  let confirmation_section = doc.getElementById("confirm-deletion-section");
  isnot(
    confirmation_section.style.display,
    "none",
    "Confirmation section did not open."
  );

  // Check if the label displays the correct data
  let confirmation_context = doc.getElementById("confirmation-context");
  // Items get listed in reverse order (inserRow(0) in a loop), so we use [0] instead of [1] here
  is(
    confirmation_context.textContent,
    REAL_DATA[0].template_friendly_name,
    "Deletion context show wrong credential name"
  );
  // Check if the delete-button has the correct context-data
  let cmd = {
    BioEnrollment: {
      DeleteEnrollment: REAL_DATA[0].template_id,
    },
  };
  is(
    confirmation_context.getAttribute("data-ctap-command"),
    JSON.stringify(cmd),
    "Confirm-button has the wrong context data"
  );

  let cancel_button = doc.getElementById("cancel-confirmation-button");
  cancel_button.click();
  is(
    confirmation_section.style.display,
    "none",
    "Confirmation section did not close."
  );
  check_bio_buttons_disabled(false);

  // Click the delete-button again
  buttons[1].click();

  // Now we tell it that we deleted all enrollments (bioEnroll: false)
  send_bio_enrollment_command({
    DeleteSuccess: { options: { bioEnroll: false } },
  });
  // Thus, all buttons should get re-enabled and the subsection should be hidden
  check_bio_buttons_disabled(false);

  let bio_enrollment_subsection = doc.getElementById(
    "bio-enrollment-list-subsection"
  );
  is(bio_enrollment_subsection.hidden, true, "Bio Enrollment List not hidden.");
});

const REAL_DATA = [
  { template_id: [248, 82], template_friendly_name: "right-index" },
  { template_id: [14, 163], template_friendly_name: "right-middle" },
];
