#!/usr/bin/env node
/**
 * mutate-runner (Level B, P18) — живая мутация одного файла под один тест.
 * baseline-GREEN до мутации (SE-LB-2: краснота атрибутируема мутации, не пред-существующему провалу);
 * мутация IN-PLACE с железобетонным восстановлением (SE-LB-3): тест импортирует РЕАЛЬНЫЙ путь, поэтому
 * мутанта надо положить туда же; оригинал держим в памяти и пишем обратно в finally + сверяем восстановление.
 * Утечка мутанта при жёстком kill ловится потребителем по несовпадению отпечатка (defense-in-depth).
 * classifyMutationResult — чистая: убит ⇔ ≥1 валидный (не loadError) мутант покраснел.
 */
import { readFileSync, writeFileSync } from 'node:fs';

export function classifyMutationResult({ baselineGreen, mutantOutcomes = [] }) {
  if (baselineGreen !== true) return { mutationKilled: false, reason: 'baseline-not-green' };
  const valid = (mutantOutcomes || []).filter((o) => o && o.loadError !== true);
  if (valid.length === 0) return { mutationKilled: false, reason: 'no-valid-mutants' };
  const killed = valid.some((o) => o.allGreen === false);
  return killed ? { mutationKilled: true, reason: 'ok' } : { mutationKilled: false, reason: 'mutation-survived' };
}

/**
 * Прогнать мутацию для filePath под testFile. generate/runTest инъектируются (юнит-тесты — фейки;
 * live main подаёт generateMutants и (tf)=>runVitestJson(tf, gitCwd)). testFile передаётся в runTest.
 */
export function runMutationForFile({ filePath, testFile, generate, runTest }) {
  const original = readFileSync(filePath, 'utf-8');
  const baseline = runTest(testFile);
  if (!(baseline.allGreen === true && baseline.numPassed > 0)) {
    return { baselineGreen: false, testCount: baseline.numPassed || 0, mutantOutcomes: [] };
  }
  const mutants = generate(original) || [];
  const mutantOutcomes = [];
  try {
    for (const m of mutants) {
      writeFileSync(filePath, m.mutated);
      const r = runTest(testFile);
      mutantOutcomes.push({ label: m.label, allGreen: r.allGreen, loadError: r.loadError });
    }
  } finally {
    writeFileSync(filePath, original); // восстановление гарантировано
  }
  if (readFileSync(filePath, 'utf-8') !== original) {
    throw new Error('mutate-runner: восстановление файла не удалось (fail-CLOSE)');
  }
  return { baselineGreen: true, testCount: baseline.numPassed, mutantOutcomes };
}
