/**
 * spawn-worker.js — Shared helpers for parallel worker process management.
 *
 * Purpose: consolidate duplicated `resolveSfBin()` and NDJSON stdout buffering
 * logic that appeared identically in both parallel-orchestrator.js and
 * slice-parallel-orchestrator.js. Single source of truth for the SF binary
 * path resolution strategy.
 *
 * Consumer: parallel-orchestrator.js, slice-parallel-orchestrator.js.
 */
import { existsSync } from "node:fs";
import { join } from "node:path";

/**
 * Resolve the absolute path to the SF CLI binary (dist/loader.js).
 * Uses SF_BIN_PATH env var first (set by loader.ts), then falls back to
 * relative path discovery from this file's location.
 */
export function resolveSfBin() {
	if (process.env.SF_BIN_PATH && existsSync(process.env.SF_BIN_PATH)) {
		return process.env.SF_BIN_PATH;
	}
	let thisDir;
	try {
		thisDir = import.meta.dirname;
	} catch {
		thisDir = process.cwd();
	}
	const candidates = [
		join(thisDir, "..", "..", "..", "loader.js"),
		join(thisDir, "..", "..", "..", "..", "dist", "loader.js"),
	];
	for (const candidate of candidates) {
		if (existsSync(candidate)) return candidate;
	}
	return null;
}

/**
 * Attach a line-buffered NDJSON reader to a child process stdout stream.
 * Splits incoming data on newlines, calls onLine for each complete line,
 * and flushes any remaining buffer when the stream closes.
 *
 * Consumer: spawnWorker/spawnSliceWorker in each orchestrator.
 */
export function monitorNdjsonStdout(stream, onLine) {
	let buffer = "";
	stream.on("data", (data) => {
		buffer += data.toString();
		const lines = buffer.split("\n");
		buffer = lines.pop() || "";
		for (const line of lines) {
			onLine(line);
		}
	});
	stream.on("close", () => {
		if (buffer.trim()) {
			onLine(buffer);
		}
	});
}
