const { test } = require('node:test')
const assert = require('node:assert/strict')

const logic = require('../src/model/announceJobs/announceJobs.logic')
// Each leg owns its own text-building and result classification since PR 4 — a
// leg is a registration now, not a branch in the worker (MODULE_SYSTEM.md §1.8).
const discord = require('../src/utils/discordAnnounce')

// The town-crier leg's tests left with module-uo in Phase 3 — it is a MODULE's
// leg, and its text building and status classification are its business. What
// stays here is core's announce pipeline: the backoff schedule every leg shares,
// the parent-status rollup over all of a job's legs, and core's own Discord leg.
// ── classifyDiscord ──────────────────────────────────────────────────────────
test('discord classify: ok is done, every failure retries', () => {
  assert.equal(discord.classify({ ok: true, status: 200 }).outcome, 'done')
  for (const status of [400, 503, 0]) {
    assert.equal(discord.classify({ ok: false, status }).outcome, 'retry', `status ${status}`)
  }
})

// ── scheduleAfter (backoff) ──────────────────────────────────────────────────
test('scheduleAfter returns increasing delays then null at the attempt cap', () => {
  const d1 = logic.scheduleAfter(1)
  const d2 = logic.scheduleAfter(2)
  assert.ok(d1 > 0 && d2 > d1, 'delays should grow')
  // Exhausted once attempts reach MAX_ATTEMPTS.
  assert.equal(logic.scheduleAfter(logic.MAX_ATTEMPTS), null)
  assert.equal(logic.scheduleAfter(logic.MAX_ATTEMPTS + 3), null)
})

// ── rollupStatus ─────────────────────────────────────────────────────────────
// Takes the LIST of leg statuses, not two named legs: which legs exist is what a
// module decides (MODULE_SYSTEM.md §1.8).
test('rollupStatus derives the parent status from its legs', () => {
  assert.equal(logic.rollupStatus(['done', 'done']), 'done')
  assert.equal(logic.rollupStatus(['failed', 'failed']), 'failed')
  assert.equal(logic.rollupStatus(['pending', 'pending']), 'pending')
  // One terminal, the others not matching → partial.
  assert.equal(logic.rollupStatus(['done', 'pending']), 'partial')
  assert.equal(logic.rollupStatus(['pending', 'failed']), 'partial')
  assert.equal(logic.rollupStatus(['done', 'failed']), 'partial')
})

test('rollupStatus generalises past two legs', () => {
  assert.equal(logic.rollupStatus(['done', 'done', 'done']), 'done')
  assert.equal(logic.rollupStatus(['done', 'done', 'pending']), 'partial')
  assert.equal(logic.rollupStatus(['pending', 'pending', 'pending']), 'pending')
  assert.equal(logic.rollupStatus(['failed', 'failed', 'failed']), 'failed')
  // A single leg is not a special case.
  assert.equal(logic.rollupStatus(['pending']), 'pending')
  assert.equal(logic.rollupStatus(['done']), 'done')
  // No legs registered at all: nothing is left to deliver, so the job is done
  // rather than pending forever on a leg that does not exist.
  assert.equal(logic.rollupStatus([]), 'done')
})
