// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.

/*
Ensure the `--firefox.preference=network.http.http3.enable:true` is
set for this test.
*/

async function getNumLoaded(commands) {
  return commands.js.run(`
    let sum = 0;
    document.querySelectorAll("#imgContainer img").forEach(e => {
      sum += (e.complete && e.naturalHeight != 0) ? 1 : 0;
    });
    return sum;
  `);
}

async function waitForImgLoadEnd(
  prevCount,
  maxStableCount,
  timeout,
  commands,
  context
) {
  let starttime = await commands.js.run(`return performance.now();`);
  let endtime = await commands.js.run(`return performance.now();`);
  let changing = true;
  let newCount = -1;
  let stableCount = 0;

  while (
    ((await commands.js.run(`return performance.now();`)) - starttime <
      timeout) &
    changing
  ) {
    // Wait a bit before making another round
    await commands.wait.byTime(100);
    newCount = await getNumLoaded(commands);
    context.log.debug(`${newCount}, ${prevCount}, ${stableCount}`);

    // Check if we are approaching stability
    if (newCount == prevCount) {
      // Gather the end time now
      if (stableCount == 0) {
        endtime = await commands.js.run(`return performance.now();`);
      }
      stableCount++;
    } else {
      prevCount = newCount;
      stableCount = 0;
    }

    if (stableCount >= maxStableCount) {
      // Stability achieved
      changing = false;
    }
  }

  return {
    start: starttime,
    end: endtime,
    numResources: newCount,
  };
}

async function test(context, commands) {
  let rootUrl = "https://lucaspardue.com/quictilesfetch.html";
  let cycles = 5;

  if (
    typeof context.options.browsertime !== "undefined" &&
    typeof context.options.browsertime.cycles !== "undefined"
  ) {
    cycles = context.options.browsertime.cycles;
  }

  // Make firefox learn of HTTP/3 server
  // XXX: Need to build an HTTP/3-specific conditioned profile
  // to handle these pre-navigations.
  await commands.navigate(rootUrl);

  let combos = [
    [100, 1],
    [100, 100],
    [300, 300],
  ];
  for (let cycle = 0; cycle < cycles; cycle++) {
    for (let combo = 0; combo < combos.length; combo++) {
      await commands.measure.start("pageload");
      await commands.navigate(rootUrl);
      await commands.measure.stop();
      let last = commands.measure.result.length - 1;
      commands.measure.result[last].browserScripts.pageinfo.url =
        `LucasQUIC (r=${combos[combo][0]}, p=${combos[combo][1]})`;

      // Set the input fields
      await commands.js.runAndWait(`
        document.querySelector("#maxReq").setAttribute(
          "value",
          ${combos[combo][0]}
        )
      `);
      await commands.js.runAndWait(`
        document.querySelector("#reqGroup").setAttribute(
          "value",
          ${combos[combo][1]}
        )
      `);

      // Start the test and wait for the images to finish loading
      commands.click.byJs(`document.querySelector("button")`);
      let results = await waitForImgLoadEnd(0, 40, 120000, commands, context);

      commands.measure.result[last].browserScripts.pageinfo.resourceLoadTime =
        results.end - results.start;
      commands.measure.result[last].browserScripts.pageinfo.imagesLoaded =
        results.numResources;
      commands.measure.result[last].browserScripts.pageinfo.imagesMissed =
        combos[combo][0] - results.numResources;
    }
  }
}

module.exports = {
  test,
  owner: "Network Team",
  name: "lq-fetch",
  component: "netwerk",
  description: "Measures the amount of time it takes to load a set of images.",
};
