addEventListener("fetch", (event) => {
  function findBestMatch(preference, options) {
    let bestMatch = "";
    let highestQuality = -1;

    for (let p of preference) {
      for (let o of options) {
        if (o.includes(p)) {
          let quality = 1;
          // Check if quality parameter is on the option
          let qIndex = o.indexOf("q=");
          // If it is, set quality to its value
          if (qIndex > -1) {
            quality = parseFloat(o.substring(qIndex + 2));
          }
          if (quality > highestQuality) {
            bestMatch = o.split(";")[0];
            highestQuality = quality;
          }
        }
      }
    }

    return bestMatch;
  }

  // Get the request from the client.
  const originalReq = event.request;

  let url = new URL(event.request.url);

  // Filter the query string to only include query parameters that are valid for your site
  let searchEntries = url.searchParams.entries();
  let filteredEntries = Array.from(searchEntries).filter((entry) =>
    ["query", "page", "foo"].includes(entry[0])
  );
  let filteredParams = new URLSearchParams(filteredEntries);

  // Lowercase specific query param values
  let fooValue = filteredParams.get("foo");
  if (fooValue) {
    filteredParams.set("foo", fooValue.toLocaleLowerCase());
  }

  // Sort the querystring params in alphabetical order
  filteredParams.sort();

  // Create a new Request object with a sorted URL.
  url.search = filteredParams;
  const newReq = new Request(url, originalReq);

  // Remove headers that you want to avoid using to vary responses
  newReq.headers.delete("user-agent");
  newReq.headers.delete("cookie");

  // Normalise headers that you may vary on.
  let acceptValue = newReq.headers.get("accept-language");

  if (acceptValue) {
    const preference = ["en", "de", "fr", "nl"];
    // Find the best match between preference and accept-language header
    const options = acceptValue.split(",").map((opt) => opt.trim());
    // Find the best match between preference and accept-encoding header
    let selection = findBestMatch(preference, options);
    // Fallback if no preference match was found.
    if (selection === "") {
      selection = "de";
    }

    newReq.headers.set("accept-language", selection);
  }

  acceptValue = newReq.headers.get("accept-encoding");
  if (acceptValue) {
    const preference = ["br", "compress", "deflate", "gzip", "identity"];
    const options = acceptValue.split(",").map((opt) => opt.trim());

    // Find the best match between preference and accept-encoding header
    let selection = findBestMatch(preference, options);

    // Fallback if no matching preference is expressed for accept-encoding.
    if (selection === "") {
      selection = "identity";
    }

    newReq.headers.set("accept-encoding", selection);
  }

  acceptValue = newReq.headers.get("accept-charset");
  if (acceptValue) {
    const preference = ["iso-8859-5", "iso-8859-2", "utf-8"];
    const options = acceptValue.split(",").map((opt) => opt.trim());
    // Find the best match between preference and accept-charset header
    let selection = findBestMatch(preference, options);

    // Fallback if no preference is expressed for accept-charset.
    if (selection === "") {
      selection = "utf-8";
    }

    newReq.headers.set("accept-charset", selection);
  }

  // Print out the request url and headers for debugging. Disable for production use to avoid overhead.
  console.log(newReq.url);
  newReq.headers.forEach((value, name) => console.log(name + ": " + value));

  // Send the request to `origin_0`.
  const backendResponse = fetch(newReq, {
    backend: "origin_0"
  });

  // Send the backend response back to the client.
  event.respondWith(backendResponse);
});