import { test } from 'node:test';
import assert from 'node:assert/strict';

const { coalesce } = await import('../src/coalesce.js');

const tick = (ms = 5) => new Promise((r) => setTimeout(r, ms));

test('coalesce: nie mehr als ein Lauf gleichzeitig pro Key', async () => {
  let active = 0, maxActive = 0, runs = 0;
  const fn = async () => { active++; maxActive = Math.max(maxActive, active); await tick(10); runs++; active--; return runs; };

  // 5 gleichzeitige Aufrufe.
  await Promise.all(Array.from({ length: 5 }, () => coalesce('k1', fn)));
  assert.equal(maxActive, 1, 'parallele Läufe');
  // Erster Lauf bedient den ersten Aufruf; die 4 während des Laufs eingetroffenen
  // teilen sich GENAU EINEN nachgelagerten Lauf → insgesamt 2.
  assert.equal(runs, 2);
});

test('coalesce: Wartende teilen sich das Ergebnis des nachgelagerten Laufs', async () => {
  let n = 0;
  const fn = async () => { await tick(10); return ++n; };
  const first = coalesce('k2', fn);          // startet sofort → Ergebnis 1
  await tick(2);                              // sicherstellen, dass er läuft
  const a = coalesce('k2', fn);              // wartet → nachgelagerter Lauf
  const b = coalesce('k2', fn);              // wartet → selber Lauf wie a
  assert.equal(await first, 1);
  const [ra, rb] = await Promise.all([a, b]);
  assert.equal(ra, 2);
  assert.equal(rb, 2);                        // a und b teilen sich Lauf 2
});

test('coalesce: Fehler wird an die Wartenden propagiert, Key bleibt nutzbar', async () => {
  let fail = true;
  const fn = async () => { await tick(5); if (fail) throw new Error('boom'); return 'ok'; };
  await assert.rejects(() => coalesce('k3', fn), /boom/);
  fail = false;
  assert.equal(await coalesce('k3', fn), 'ok');   // danach wieder verwendbar
});

test('coalesce: verschiedene Keys laufen unabhängig', async () => {
  const fn = async () => { await tick(5); return 'done'; };
  const [x, y] = await Promise.all([coalesce('kA', fn), coalesce('kB', fn)]);
  assert.equal(x, 'done');
  assert.equal(y, 'done');
});
