/**
 * SET 45b — Substrate handoff page formatter.
 *
 * Formats the deterministic investigation trail so the next model draw starts
 * where the substrate stopped. Metrics strip / efficacy live in statsAggregate
 * (45a/45c) to avoid circular imports with superbuffer.
 */
import type { MechanicalFixAttempt } from './substrate';

export interface SubstrateHandoffAttempt {
  /** Handler / class family label (e.g. import-rewire, assertion|eq). */
  handler: string;
  status: MechanicalFixAttempt['status'] | string;
  reason?: string;
  /** Named options the model should choose among (not rediscover). */
  candidateSites?: string[];
  note?: string;
}

export interface SubstrateHandoff {
  classKey: string;
  stratum?: string;
  attempts: SubstrateHandoffAttempt[];
  /** Preformatted refusal lines (optional; also derived from refused attempts). */
  refusals?: string[];
  /** Candidate edits considered but rejected (not applied). */
  rejectedCandidates?: string[];
  /** Playbook steps already ruled out. */
  ruledOutPlaybook?: string[];
  /** Spec constants (43b) when available. */
  constants?: string[];
}

/** `import-rewire: refused — 2 candidate sites: src/a.ts, src/b.ts` */
export function formatSubstrateRefusal(opts: {
  action: string;
  reason?: string;
  candidateSites?: string[];
}): string {
  const action = (opts.action || 'substrate').trim() || 'substrate';
  const sites = (opts.candidateSites ?? []).map(s => s.trim()).filter(Boolean);
  if (sites.length) {
    return `${action}: refused — ${sites.length} candidate site${sites.length === 1 ? '' : 's'}: ${sites.join(', ')}`;
  }
  return `${action}: refused — ${(opts.reason ?? 'unproven').trim() || 'unproven'}`;
}

/** True when handoff has a deterministic trail worth packing (no empty-page noise). */
export function hasSubstrateHandoffHistory(h: SubstrateHandoff | null | undefined): boolean {
  if (!h) return false;
  return (
    Boolean(h.classKey)
    || h.attempts.length > 0
    || (h.refusals?.length ?? 0) > 0
    || (h.rejectedCandidates?.length ?? 0) > 0
    || (h.ruledOutPlaybook?.length ?? 0) > 0
    || (h.constants?.length ?? 0) > 0
  );
}

/** @deprecated alias — prefer hasSubstrateHandoffHistory */
export const hasSubstrateHandoff = hasSubstrateHandoffHistory;

function formatAttemptLine(a: SubstrateHandoffAttempt): string {
  const sites = a.candidateSites?.filter(Boolean) ?? [];
  if (a.status === 'refused' && sites.length) {
    return (
      `${a.handler}: refused — ${sites.length} candidate site`
      + `${sites.length === 1 ? '' : 's'}: ${sites.join(', ')}`
    );
  }
  const reason = a.reason ? ` — ${a.reason}` : '';
  const note = a.note ? ` — ${a.note}` : '';
  return `${a.handler}: ${a.status}${reason}${note}`;
}

/**
 * Full page text including "Page substrate — …" header.
 * Returns empty string when there is nothing to hand off.
 */
export function formatSubstrateHandoffPage(h: SubstrateHandoff | null | undefined): string {
  if (!hasSubstrateHandoffHistory(h) || !h) return '';
  const CAP = 800;
  const lines: string[] = [
    'Page substrate — deterministic handoff (finish this investigation):',
    `classification: ${h.classKey}${h.stratum ? ` · stratum=${h.stratum}` : ''}`,
  ];
  const deferred: string[] = [];
  const append = (line: string): void => {
    if (lines.join('\n').length + line.length + 1 <= CAP) lines.push(line);
    else deferred.push(line);
  };
  if (h.attempts.length) {
    append('mechanical attempts (most recent first):');
    for (const a of [...h.attempts].reverse()) append(`  - ${formatAttemptLine(a)}`);
  }
  const refusalLines = h.refusals?.length
    ? h.refusals
    : h.attempts.filter(a => a.status === 'refused').map(formatAttemptLine);
  if (refusalLines.length) {
    append('refusals (with reason):');
    for (const r of refusalLines) append(`  - ${r}`);
  }
  if (h.rejectedCandidates?.length) {
    append('candidate edits considered-but-rejected:');
    for (const c of h.rejectedCandidates) append(`  - ${c}`);
  }
  if (h.ruledOutPlaybook?.length) {
    append('playbook steps ruled out:');
    for (const p of h.ruledOutPlaybook) append(`  - ${p}`);
  }
  if (h.constants?.length) {
    append('constants (spec literals):');
    for (const c of h.constants) append(`  - ${c}`);
  }
  if (!deferred.length) return lines.join('\n');
  const marker = `… (${deferred.length} item(s) elided at cap)`;
  const page = lines.join('\n');
  return `${page.slice(0, Math.max(0, CAP - marker.length - 1))}\n${marker}`;
}

/** Build a handoff record from live substrate attempts + optional extras. */
export function buildSubstrateHandoff(input: {
  classKey: string;
  stratum?: string;
  attempts: SubstrateHandoffAttempt[];
  refusals?: string[];
  rejectedCandidates?: string[];
  ruledOutPlaybook?: string[];
  constants?: string[];
}): SubstrateHandoff | null {
  const refusals = input.refusals?.length
    ? input.refusals
    : input.attempts
      .filter(a => a.status === 'refused')
      .map(a => formatSubstrateRefusal({
        action: a.handler,
        reason: a.reason,
        candidateSites: a.candidateSites,
      }));
  const h: SubstrateHandoff = {
    classKey: input.classKey,
    stratum: input.stratum,
    attempts: input.attempts,
    refusals: refusals.length ? refusals : undefined,
    rejectedCandidates: input.rejectedCandidates,
    ruledOutPlaybook: input.ruledOutPlaybook,
    constants: input.constants?.length ? input.constants : undefined,
  };
  return hasSubstrateHandoffHistory(h) ? h : null;
}
