/**
 * Lasttest mot lokal API (körs mot dist-bygget):
 *   node apps/api/dist/index.js &   # starta API:t först
 *   node scripts/loadtest.mjs
 *
 * Tre scenarier: oautentiserad healthz, autentiserad receptlista (DB + översättnings-
 * upplösning) och rekommendationer (tyngsta läsvägen: lager + motor + förklaringar).
 * Trösklar (encore-server, 1 CPU-klass): p99 < 500 ms, inga fel, > 100 req/s på recept.
 */
import autocannon from "autocannon";

const BASE = process.env.API_BASE_URL ?? "http://localhost:4000";

async function json(path, options = {}) {
  const res = await fetch(`${BASE}${path}`, {
    ...options,
    headers: { "content-type": "application/json", ...(options.headers ?? {}) },
    body: options.body ? JSON.stringify(options.body) : undefined,
  });
  if (!res.ok) throw new Error(`${path} -> ${res.status}`);
  return res.json();
}

// --- Setup: användare med hushåll + lite lager, så läsvägarna är realistiska ---
const email = `loadtest-${process.pid}@example.com`;
let auth;
try {
  auth = await json("/v1/auth/register", {
    method: "POST",
    body: { email, password: "Lasttest1234!", displayName: "Lasttest" },
  });
} catch {
  auth = await json("/v1/auth/login", {
    method: "POST",
    body: { email, password: "Lasttest1234!" },
  });
}
const token = auth.accessToken;
const headers = { authorization: `Bearer ${token}` };
const hh = await json("/v1/households", { method: "POST", headers, body: { name: "Lasttest" } });
const full = await json(`/v1/households/${hh.id}`, { headers });
const locId = full.storageLocations[0].id;
for (const [ing, qty] of [["pasta_spaghetti", 500], ["minced_beef", 400], ["onion_yellow", 3]]) {
  await json("/v1/inventory/items", {
    method: "POST",
    headers,
    body: {
      ingredientId: ing,
      displayName: ing,
      storageLocationId: locId,
      quantity: qty,
      unit: qty > 10 ? "GRAM" : "COUNT",
    },
  }).catch(() => {});
}

// --- Scenarier ---
const scenarios = [
  { name: "healthz (baslinje)", path: "/healthz", auth: false },
  { name: "GET /v1/recipes (lista + i18n-upplösning)", path: "/v1/recipes?limit=20", auth: true },
  {
    name: "GET /v1/recommendations/what-to-eat (tyngsta läsvägen)",
    path: "/v1/recommendations/what-to-eat?meal=dinner",
    auth: true,
  },
];

const results = [];
for (const s of scenarios) {
  const r = await autocannon({
    url: `${BASE}${s.path}`,
    connections: 25,
    duration: 10,
    headers: s.auth ? headers : {},
  });
  results.push({
    scenario: s.name,
    reqPerSec: Math.round(r.requests.average),
    latencyP50: r.latency.p50,
    latencyP99: r.latency.p99,
    errors: r.errors + r.non2xx,
  });
  console.log(
    `${s.name}: ${Math.round(r.requests.average)} req/s, p50 ${r.latency.p50} ms, p99 ${r.latency.p99} ms, fel ${r.errors + r.non2xx}`,
  );
}

// --- Trösklar ---
const failures = [];
for (const r of results) {
  if (r.errors > 0) failures.push(`${r.scenario}: ${r.errors} fel`);
  if (r.latencyP99 > 500) failures.push(`${r.scenario}: p99 ${r.latencyP99} ms > 500 ms`);
}
const recipes = results[1];
if (recipes && recipes.reqPerSec < 100) {
  failures.push(`receptlistan: ${recipes.reqPerSec} req/s < 100`);
}

console.log("\n| Scenario | req/s | p50 | p99 | fel |");
console.log("| -------- | ----- | --- | --- | --- |");
for (const r of results) {
  console.log(
    `| ${r.scenario} | ${r.reqPerSec} | ${r.latencyP50} ms | ${r.latencyP99} ms | ${r.errors} |`,
  );
}
if (failures.length) {
  console.error("\nUNDERKÄND:\n" + failures.map((f) => `  ✗ ${f}`).join("\n"));
  process.exit(1);
}
console.log("\nGODKÄND – alla trösklar klarade.");
