/**
 * SET 28b / 32e — fill-attempt honesty. Every fill attempt must log the cases
 * it targets, and every drop message must state the TRUE draw / batch counts
 * — never claim retries that didn't happen.
 */

/** `fill batch: targets ["A", "B"]` — emitted BEFORE a batch is drawn, so a
 * dropped case always has at least one attempt event naming it, even if
 * every draw in the batch subsequently throws. */
export function formatFillBatchTargets(names: string[], suffix?: string): string {
  const list = names.map(n => `"${n}"`).join(', ');
  return `fill batch: targets [${list}]${suffix ? ` (${suffix})` : ''}`;
}

/**
 * SET 32e.i — one vocabulary for the drop line:
 *   `planned case "X" unfilled after N draws (C candidate batch(es) + F fallback batch(es)) — dropped`
 *
 * `draws` = individual model calls (one per permutation-temp candidate, across
 *   every batch/redraw that targeted this case).
 * `candidateBatches` = K-draw permutation batches that TARGETED this case.
 * `fallbackBatches` = plan-bound-fallback / redraw batches that TARGETED this
 *   case (structural fallback + IR redraw sweeps).
 *
 * A case with zero draws was never actually reached — a materially different
 * (and more honest) failure than "tried and failed".
 */
export function formatFillDropMessage(
  name: string,
  draws: number,
  candidateBatches: number,
  fallbackBatches: number,
): string {
  if (draws <= 0) {
    return `planned case "${name}" never drawn — dropped (plan exceeded fill budget)`;
  }
  const parts: string[] = [];
  parts.push(`${candidateBatches} candidate batch${candidateBatches === 1 ? '' : 'es'}`);
  parts.push(`${fallbackBatches} fallback batch${fallbackBatches === 1 ? '' : 'es'}`);
  return `planned case "${name}" unfilled after ${draws} draw${draws === 1 ? '' : 's'} `
    + `(${parts.join(' + ')}) — dropped`;
}
