// Characterization test: addParticipant + pause/resume corrupts turn rotation.
// Audit found 56-77 violations/100 rounds starting round 20 in pure turn.js
// simulation. Visible in live replay (round 10: 17 turns, 6 duped actors,
// R-series stuck repeating forever).
//
// This test uses FRESH ids (crypto.randomUUID equivalent) — NOT the audit's
// self-inflicted dup (loop spun while paused, re-added same `r${totalTurns}`).
// Validates real bug reachable via normal UI flow (DM adds monster while paused,
// resumes).
//
// Rewritten for async turn.js API: funcs are awaited, take ctx, write own logs.

const shared = require('@ttrpg/shared');
const { mockCtx } = require('./_helpers');
const { startEncounter, nextTurn, togglePause, addParticipant, makeParticipant } = shared;

function p(id, initiative, extra = {}) {
  return makeParticipant({
    id, name: id, type: 'monster',
    initiative, maxHp: 100, currentHp: 100,
    ...extra,
  });
}

function enc(ps) {
  return {
    name: 'T', participants: ps,
    isStarted: false, isPaused: false,
    round: 0, currentTurnParticipantId: null, turnOrderIds: [],
  };
}

describe('addParticipant + pause/resume rotation corruption', () => {
  test('add fresh participant while paused, resume, rotation completes full cycle', async () => {
    const { ctx } = mockCtx();
    const ps = [p('a', 20), p('b', 15), p('c', 10)];
    let e = enc(ps);
    e = await startEncounter(e, ctx);
    const baseOrder = e.turnOrderIds.slice(); // [a,b,c]

    e = await nextTurn(e, ctx); // current=b
    e = await togglePause(e, ctx); // pause

    // add fresh participant x (initiative 25, would sort first)
    const x = p('x', 25);
    e = await addParticipant(e, x, ctx);
    e = await togglePause(e, ctx); // resume (rebuilds order)

    // after resume, complete one full round: visit each active participant once
    const visited = [e.currentTurnParticipantId];
    for (let i = 0; i < e.turnOrderIds.length - 1; i++) {
      e = await nextTurn(e, ctx);
      visited.push(e.currentTurnParticipantId);
    }
    const uniq = new Set(visited);
    // EXPECT: 4 unique (a,b,c,x). BUG: rotation may not visit all.
    expect(uniq.size).toBe(e.turnOrderIds.length);
  });

  test('multiple adds while paused, resume, rotation visits all', async () => {
    const { ctx } = mockCtx();
    const ps = [p('a', 20), p('b', 15), p('c', 10)];
    let e = enc(ps);
    e = await startEncounter(e, ctx);

    e = await nextTurn(e, ctx); // current=b
    e = await togglePause(e, ctx); // pause

    // add 3 fresh participants
    for (const id of ['x', 'y', 'z']) {
      const np = p(id, 5 + Math.floor(Math.random() * 30));
      e = await addParticipant(e, np, ctx);
    }
    e = await togglePause(e, ctx); // resume

    const visited = [e.currentTurnParticipantId];
    for (let i = 0; i < e.turnOrderIds.length + 2; i++) {
      e = await nextTurn(e, ctx);
      visited.push(e.currentTurnParticipantId);
    }
    const uniq = new Set(visited);
    // EXPECT: all 6 participants reachable. BUG: some stuck/repeated.
    expect(uniq.size).toBe(e.turnOrderIds.length);
  });

  test('add while running, then pause+resume, rotation stays valid', async () => {
    const { ctx } = mockCtx();
    const ps = [p('a', 20), p('b', 15), p('c', 10)];
    let e = enc(ps);
    e = await startEncounter(e, ctx);

    e = await nextTurn(e, ctx); // current=b
    const x = p('x', 25);
    e = await addParticipant(e, x, ctx); // add while running
    e = await togglePause(e, ctx); // pause
    e = await togglePause(e, ctx); // resume

    const visited = [e.currentTurnParticipantId];
    for (let i = 0; i < e.turnOrderIds.length + 2; i++) {
      e = await nextTurn(e, ctx);
      visited.push(e.currentTurnParticipantId);
    }
    const uniq = new Set(visited);
    expect(uniq.size).toBe(e.turnOrderIds.length);
  });
});
