/**
 * tool-helpers.js — Shared low-level utilities for SF tool handlers.
 *
 * Purpose: consolidate helpers that appear in multiple tool handler files
 * (complete-task.js, complete-slice.js, etc.) to avoid silent divergence.
 *
 * Consumer: complete-task.js, complete-slice.js, and any future tool that
 * writes summary files or formats error messages.
 */
import { promises as fs, constants as fsConstants } from "node:fs";
import { dirname } from "node:path";
import { getErrorMessage } from "../error-utils.js";
import { appendEvent } from "../workflow-events.js";
import { logWarning } from "../workflow-logger.js";
import { writeManifest } from "../workflow-manifest.js";
import { renderAllProjections } from "../workflow-projections.js";

/**
 * Ensure the parent directory of filePath exists and is writable.
 * Creates missing directories with recursive mkdir before checking access.
 *
 * Purpose: guard summary-file writes so the error message names the directory
 * rather than producing a cryptic ENOENT or EACCES on the file itself.
 *
 * Consumer: complete-task.js, complete-slice.js writeSummaryBeforeDb helpers.
 */
export async function ensureWritableParent(filePath) {
	const parentDir = dirname(filePath);
	await fs.mkdir(parentDir, { recursive: true });
	await fs.access(parentDir, fsConstants.W_OK);
}

/**
 * Extract a human-readable message from an unknown caught value.
 *
 * Purpose: produce a string regardless of whether the thrown value is an
 * Error instance or a plain string/object, so callers don't need a ternary.
 *
 * Consumer: complete-task.js, complete-slice.js error formatting.
 */
export const errorMessage = getErrorMessage;

/**
 * Run the standard post-mutation hook: project all projections, write the
 * manifest, and append an event to the workflow log.
 *
 * Purpose: the three-step sequence (renderAllProjections + writeManifest +
 * appendEvent) appears in every tool that mutates planning state. Extracting
 * it here prevents the steps from drifting independently across tool files.
 *
 * Consumer: plan-task.js, plan-slice.js, plan-milestone.js, replan-slice.js,
 * reassess-roadmap.js, reopen-slice.js, reopen-task.js, reopen-milestone.js.
 *
 * @param {string} basePath - Project base path.
 * @param {string} milestoneId - Milestone ID for projection scoping.
 * @param {object} event - Full event object passed to appendEvent.
 * @param {{ caller: string }} opts - caller is the tool name used in the warning message.
 */
export async function runPostMutationHook(
	basePath,
	milestoneId,
	event,
	{ caller },
) {
	try {
		await renderAllProjections(basePath, milestoneId);
		writeManifest(basePath);
		appendEvent(basePath, event);
	} catch (hookErr) {
		logWarning(
			"tool",
			`${caller} post-mutation hook warning: ${hookErr.message}`,
		);
	}
}
