#!/usr/bin/env node
/**
 * produce-verify-receipt (G1) — производитель подписанной verify-расписки.
 * Чистое ядро buildVerifyReceipt: настоящий green ⇔ suitePassed===true И есть ключ.
 * I/O-обёртка main сама прогоняет сюиту (флаг не от контроллера, SE-G1-5), считает
 * fingerprint staged-diff, инкрементит occurrence, персистит в protected runtime.
 *
 * Файл расписки — ЕДИНЫЙ `~/.claude/runtime/verify-receipt.json` (НЕ session-scoped):
 * producer (CLI) не получает session_id из stdin как consumer-хук, поэтому единый путь
 * исключает рассинхрон. Безопасно для Level A — свежесть держит fingerprint (старая
 * расписка ≠ текущему staged-diff → stale-fingerprint → block у consumer).
 */
import { signVerifyReceipt } from './verify-receipt.mjs';
import { codeFingerprint } from './criterion-green.mjs';
import { execFileSync, execSync } from 'node:child_process';
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
import { join } from 'node:path';
import { homedir } from 'node:os';
import { fileURLToPath } from 'node:url';

export function buildVerifyReceipt({ codeFingerprint: fp, lastOccurrence = 0, suitePassed = false, signerKey } = {}) {
  if (suitePassed !== true) return { ok: false, reason: 'suite-not-passed' };
  const occurrence = lastOccurrence + 1;
  const receipt = signVerifyReceipt({ code_fingerprint: fp, occurrence }, signerKey);
  if (!receipt) return { ok: false, reason: 'no-signer-key' };
  return { ok: true, receipt };
}

/** Отпечаток staged-diff: sha256 канонизированной карты {путь: содержимое} (Δ2 через codeFingerprint). */
export function stagedFingerprint(fileContents = {}) {
  return codeFingerprint(fileContents);
}

const RECEIPT_FILE = 'verify-receipt.json';

function gitTopLevel() {
  return execFileSync('git', ['rev-parse', '--show-toplevel'], { encoding: 'utf-8' }).trim();
}
function stagedFiles(gitCwd) {
  return execFileSync('git', ['-C', gitCwd, 'diff', '--staged', '--name-only'], { encoding: 'utf-8' })
    .split(/\r?\n/).map((s) => s.trim()).filter(Boolean);
}
function stagedContents(gitCwd, files) {
  const map = {};
  for (const f of files) { try { map[f] = readFileSync(join(gitCwd, f), 'utf-8'); } catch { /* deleted/binary — skip */ } }
  return map;
}

/** I/O-main: staged → fingerprint → прогон сюиты → buildVerifyReceipt → персист в protected runtime. */
async function main() {
  const dir = join(homedir(), '.claude', 'runtime');
  const path = join(dir, RECEIPT_FILE);
  const gitCwd = gitTopLevel();
  const fp = stagedFingerprint(stagedContents(gitCwd, stagedFiles(gitCwd)));
  // Producer САМ прогоняет сюиту (SE-G1-5: флаг не от контроллера). Exit 0 = passed.
  let suitePassed = false;
  try {
    // Windows-safe (SE-G1-5 сохранён: флаг не от контроллера): npx — это npx.cmd, и
    // execFileSync('npx') без shell его НЕ находит → бросает → suite-not-passed навсегда.
    // execSync со строкой + кавычки на путях (в пути репо есть пробелы) запускает реально.
    const appRoot = join(gitCwd, 'app');
    const cfg = join(gitCwd, 'app', 'vitest.config.tools.mjs');
    execSync(`npx vitest run --root "${appRoot}" --config "${cfg}" --reporter dot`,
      { cwd: gitCwd, stdio: 'ignore' });
    suitePassed = true;
  } catch { suitePassed = false; }
  const { resolveReceiptKey } = await import('./receipt-key-config.mjs');
  let last = 0;
  if (existsSync(path)) { try { last = JSON.parse(readFileSync(path, 'utf-8')).occurrence || 0; } catch { last = 0; } }
  const r = buildVerifyReceipt({ codeFingerprint: fp, lastOccurrence: last, suitePassed, signerKey: resolveReceiptKey() });
  try { mkdirSync(dir, { recursive: true }); } catch {}
  if (r.ok) {
    writeFileSync(path, JSON.stringify(r.receipt));
    process.stdout.write(`[produce-verify-receipt] signed GREEN: fp=${fp.slice(0, 12)} occ=${r.receipt.occurrence}\n`);
  } else {
    process.stdout.write(`[produce-verify-receipt] NOT signed: ${r.reason}\n`);
  }
  process.exit(0);
}

const isCli = process.argv[1] && fileURLToPath(import.meta.url) === process.argv[1];
if (isCli) main();
