import { ConfigSchema, init_schema } from "../../../config/schema.js";
import { loadConfig, saveConfig } from "../../../config/loader.js";
import { diffConfigPaths } from "../../../config/diff.js";
import "../../../config/index.js";
import { SETUP_EXIT } from "./types.js";
import { emitOutcome } from "./output.js";
import { isPromptCancelled } from "./prompts.js";
//#region src/cli/commands/setup-shared/runner.ts
init_schema();
/** Thrown by a {@link SetupMutator.mutate} to fail the run with a clean message. */
var SetupValidationError = class extends Error {
	errors;
	constructor(errors) {
		const list = Array.isArray(errors) ? errors : typeof errors === "string" ? [{ message: errors }] : [errors];
		super(list.map((e) => e.path ? `[${e.path}] ${e.message}` : e.message).join("; "));
		this.name = "SetupValidationError";
		this.errors = list;
	}
};
function zodErrorToSetupErrors(err) {
	return err.issues.map((issue) => ({
		path: issue.path.join(".") || void 0,
		message: issue.message
	}));
}
/**
* Headless setup pipeline — load → clone → mutate → validate(zod) → diff →
* (write | dry-run) → outcome. Returns the {@link SetupOutcome} without any
* I/O side effects (no stdout, no `process.exitCode`).
*
* Used by CLI setup commands via {@link runSetup}. Keep this side-effect-free
* so it stays safe to call from tests and other programmatic callers.
*
* Custom errors thrown by the mutator surface as `errors[]` on the outcome:
*   - `SetupValidationError` — explicit `{path?, message}[]` entries
*   - `ExitPromptError` (from `@inquirer/prompts`) — surfaced as "Cancelled by user"
*   - any other `Error` — the message is used verbatim
*/
async function runSetupHeadless(args) {
	const { configPath, mutator, options } = args;
	let before;
	try {
		before = loadConfig(configPath);
	} catch (error) {
		return {
			ok: false,
			action: mutator.action,
			domain: mutator.domain,
			target: mutator.target,
			changedPaths: [],
			dryRun: options.dryRun,
			errors: [{ message: `Failed to load config: ${error.message}` }]
		};
	}
	const baselineParsed = ConfigSchema.safeParse(structuredClone(before));
	const baseline = baselineParsed.success ? baselineParsed.data : before;
	const cloneBefore = structuredClone(before);
	let mutated;
	try {
		mutated = await mutator.mutate(cloneBefore);
	} catch (error) {
		if (isPromptCancelled(error)) return {
			ok: false,
			action: mutator.action,
			domain: mutator.domain,
			target: mutator.target,
			changedPaths: [],
			dryRun: options.dryRun,
			errors: [{ message: "Cancelled by user" }]
		};
		const errors = error instanceof SetupValidationError ? error.errors : [{ message: error.message }];
		return {
			ok: false,
			action: mutator.action,
			domain: mutator.domain,
			target: mutator.target,
			changedPaths: [],
			dryRun: options.dryRun,
			errors
		};
	}
	const parsed = ConfigSchema.safeParse(mutated);
	if (!parsed.success) return {
		ok: false,
		action: mutator.action,
		domain: mutator.domain,
		target: mutator.target,
		changedPaths: [],
		dryRun: options.dryRun,
		errors: zodErrorToSetupErrors(parsed.error)
	};
	const validated = parsed.data;
	const changedPaths = diffConfigPaths(baseline, validated);
	const action = changedPaths.length === 0 ? "noop" : mutator.action;
	if (changedPaths.length > 0 && !options.dryRun) try {
		await saveConfig(validated, configPath);
	} catch (error) {
		return {
			ok: false,
			action: mutator.action,
			domain: mutator.domain,
			target: mutator.target,
			changedPaths,
			dryRun: false,
			errors: [{ message: `Failed to save config: ${error.message}` }]
		};
	}
	return {
		ok: true,
		action,
		domain: mutator.domain,
		target: mutator.target,
		changedPaths,
		dryRun: options.dryRun,
		value: mutator.resultValue?.(validated),
		notes: mutator.notes?.(validated)
	};
}
/**
* CLI wrapper around {@link runSetupHeadless}: emits the outcome to stdout
* (text or single-line JSON) and sets `process.exitCode` to the standard
* setup exit codes (0 ok / 1 error / 2 cancelled).
*
* Use this from CLI command actions; use {@link runSetupHeadless} from any
* non-CLI caller (HTTP routes, library code, tests).
*/
async function runSetup(args) {
	const outcome = await runSetupHeadless(args);
	emitOutcome(outcome, args.options.json);
	if (outcome.ok) process.exitCode = SETUP_EXIT.OK;
	else if (outcome.errors?.some((e) => /cancelled/i.test(e.message))) process.exitCode = SETUP_EXIT.CANCELLED;
	else process.exitCode = SETUP_EXIT.ERROR;
	return outcome;
}
//#endregion
export { SetupValidationError, runSetup, runSetupHeadless };

//# sourceMappingURL=runner.js.map