/// <reference types="@fastly/js-compute" />

import { v4 as uuidV4 } from "uuid";
import seedrandom from "seedrandom";

const AB_TESTS = {
  itemcount: [
    { value: "10", weight: 50 },
    { value: "15", weight: 50 },
  ],
  buttonsize: [
    { value: "small", weight: 50 },
    { value: "medium", weight: 25 },
    { value: "large", weight: 25 },
  ],
};

function applyTestToVisitor(visitorId) {
  const results = {};
  for (const [testId, entries] of Object.entries(AB_TESTS)) {
    const rng = seedrandom(visitorId + testId);

    const weightsTotal = entries.reduce((acc, entry) => acc + entry.weight, 0);
    let random = rng() * weightsTotal;
    const bucket = entries.find((entry) => {
      random = random - entry.weight;
      return random < 0;
    });

    results[testId] = bucket.value;
  }
  return results;
}

addEventListener("fetch", (event) => event.respondWith(handleRequest(event)));
async function handleRequest(event) {
  const req = event.request;

  // Parse cookies from the "Cookie" header
  const cookies = (req.headers.get("Cookie") ?? "")
    .split(";")
    .reduce((acc, val) => {
      const segment = val.trim();
      const pos = segment.indexOf("=");
      if (pos !== -1) {
        const key = segment.slice(0, pos);
        const value = decodeURIComponent(segment.slice(pos + 1));
        acc[key] = value;
      }
      return acc;
    }, {});

  // Allocate the visitor a unique identifier if they don't already have one
  let newCookie = false;
  let abTestVisitorId = cookies["ab_cid"];
  if (abTestVisitorId == null) {
    abTestVisitorId = uuidV4();
    newCookie = true;
  }

  if (cookies["ab_cid"] != null) {
    // If request contained A/B cookie, then we hide it from the origin
    delete cookies["ab_cid"];
    const reqCookie = Object.entries(cookies)
      .map(([name, value]) => {
        return name + "=" + encodeURIComponent(value);
      })
      .join("; ");
    if (reqCookie !== "") {
      req.headers.set("Cookie", reqCookie);
    } else {
      req.headers.delete("Cookie");
    }
  }

  const testResults = applyTestToVisitor(abTestVisitorId);

  for (const [testId, result] of Object.entries(testResults)) {
    req.headers.set(`Fastly-ABTest-${testId}`, result);
  }

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

  if (newCookie) {
    backendResponse.headers.append(
      "Set-Cookie",
      `ab_cid=${encodeURIComponent(
        abTestVisitorId
      )}; Max-Age: 31536000; Path=/; Secure; HttpOnly`
    );
    backendResponse.headers.set("Cache-Control", "no-store");
  }

  return backendResponse;
}