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

"use strict";

// Test submitting display device changes on the device modal
const { getDevices } = require("resource://devtools/client/shared/devices.js");

const addedDevice = {
  name: "Fake Phone RDM Test",
  width: 320,
  height: 570,
  pixelRatio: 1.5,
  userAgent: "Mozilla/5.0 (Mobile; rv:39.0) Gecko/39.0 Firefox/39.0",
  touch: true,
  firefoxOS: false,
  os: "custom",
  featured: true,
};

const TEST_URL = "data:text/html;charset=utf-8,";

addRDMTask(
  TEST_URL,
  async function ({ ui }) {
    const { toolWindow } = ui;
    const { document, store } = toolWindow;
    const deviceSelector = document.getElementById("device-selector");

    await openDeviceModal(ui);

    info(
      "Checking displayed device checkboxes are checked in the device modal."
    );
    const checkedCbs = document.querySelectorAll(
      ".device-input-checkbox:checked"
    );
    const remoteList = await getDevices();

    const featuredCount = getNumberOfFeaturedDevices(remoteList);
    is(
      featuredCount,
      checkedCbs.length,
      "Got expected number of displayed devices."
    );

    for (const cb of checkedCbs) {
      ok(
        Object.keys(remoteList).filter(type => remoteList[type][cb.value]),
        cb.value + " is correctly checked."
      );
    }

    // Tests where the user adds a non-featured device
    info("Check the first unchecked device and submit new device list.");
    const uncheckedCb = document.querySelector(
      ".device-input-checkbox:not(:checked)"
    );
    const value = uncheckedCb.value;
    uncheckedCb.click();
    document.getElementById("device-close-button").click();

    ok(
      !store.getState().devices.isModalOpen,
      "The device modal is closed on submit."
    );

    info("Checking that the new device is added to the user preference list.");
    let preferredDevices = _loadPreferredDevices();
    ok(preferredDevices.added.has(value), value + " in user added list.");

    info("Checking new device is added to the device selector.");
    await testMenuItems(toolWindow, deviceSelector, menuItems => {
      is(
        menuItems.length - 1,
        featuredCount + 1,
        "Got expected number of devices in device selector."
      );

      const menuItem = findMenuItem(menuItems, value);
      ok(menuItem, value + " added to the device selector.");
    });

    info("Reopen device modal and check new device is correctly checked");
    await openDeviceModal(ui);

    const previouslyClickedCb = [
      ...document.querySelectorAll(".device-input-checkbox"),
    ].find(cb => cb.value === value);
    ok(previouslyClickedCb.checked, value + " is checked in the device modal.");

    // Tests where the user removes a featured device
    info("Uncheck the first checked device different than the previous one");
    const checkboxes = [...document.querySelectorAll(".device-input-checkbox")];
    const checkedCb = checkboxes.find(cb => {
      if (!cb.checked || cb.value == value) {
        return false;
      }
      // In the list, we have devices with similar names (e.g. "Galaxy Note 20" and "Galaxy Note 20 Ultra")
      // Given how some test helpers are using `includes` to check device names, we might
      // get positive result for "Galaxy Note 20" although it would actually match "Galaxy Note 20 Ultra".
      // To prevent such issue without modifying existing helpers, we're excluding any
      // item whose name is part of another device.
      return !checkboxes.some(
        innerCb =>
          innerCb.value !== cb.value && innerCb.value.includes(cb.value)
      );
    });
    const checkedVal = checkedCb.value;
    checkedCb.click();
    document.getElementById("device-close-button").click();

    info("Checking that the device is removed from the user preference list.");
    preferredDevices = _loadPreferredDevices();
    ok(
      preferredDevices.removed.has(checkedVal),
      checkedVal + " in removed list"
    );

    info("Checking that the device is not in the device selector.");
    await testMenuItems(toolWindow, deviceSelector, menuItems => {
      is(
        menuItems.length - 1,
        featuredCount,
        "Got expected number of devices in device selector."
      );

      const menuItem = findMenuItem(menuItems, checkedVal);
      ok(!menuItem, checkedVal + " removed from the device selector.");
    });

    info("Reopen device modal and check device is correctly unchecked");
    await openDeviceModal(ui);
    ok(
      [...document.querySelectorAll(".device-input-checkbox")].filter(
        cb => !cb.checked && cb.value === checkedVal
      )[0],
      checkedVal + " is unchecked in the device modal."
    );

    // Let's add a dummy device to simulate featured flag changes for next test
    addDeviceForTest(addedDevice);
  },
  { waitForDeviceList: true }
);

addRDMTask(
  TEST_URL,
  async function ({ ui }) {
    const { toolWindow } = ui;
    const { document } = toolWindow;

    await openDeviceModal(ui);

    const remoteList = await getDevices();
    const featuredCount = getNumberOfFeaturedDevices(remoteList);
    const preferredDevices = _loadPreferredDevices();

    // Tests to prove that reloading the RDM didn't break our device list
    info("Checking new featured device appears in the device selector.");
    const deviceSelector = document.getElementById("device-selector");
    await testMenuItems(toolWindow, deviceSelector, items => {
      is(
        items.length - 1,
        featuredCount -
          preferredDevices.removed.size +
          preferredDevices.added.size,
        "Got expected number of devices in device selector."
      );

      const added = findMenuItem(items, addedDevice.name);
      ok(added, "Dummy device added to the device selector.");

      for (const name of preferredDevices.added.keys()) {
        const menuItem = findMenuItem(items, name);
        ok(menuItem, "Device added by user still in the device selector.");
      }

      for (const name of preferredDevices.removed.keys()) {
        const menuItem = findMenuItem(items, name);
        ok(!menuItem, "Device removed by user not in the device selector.");
      }
    });
  },
  { waitForDeviceList: true }
);

/**
 * Returns the number of featured devices
 *
 * @param {Map} devicesByType: Map of devices, keyed by type (as returned by getDevices)
 * @returns {Integer}
 */
function getNumberOfFeaturedDevices(devicesByType) {
  let count = 0;
  const devices = [...devicesByType.values()].flat();
  for (const device of devices) {
    if (device.featured && device.os != "fxos") {
      count++;
    }
  }
  return count;
}
