// SF — Deep planning mode — Helper to set planning_depth in .sf/preferences.yaml.
//
// Persists the user's deep-mode opt-in across sessions. Reads the existing
// preferences file (if any), parses its YAML, sets/updates planning_depth,
// and writes the full YAML back.
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { dirname, join } from "node:path";
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
import { getErrorMessage } from "./error-utils.js";
import { sfRoot } from "./paths.js";
import { logWarning } from "./workflow-logger.js";

/**
 * Resolve the path to the project-level preferences file.
 */
function getProjectSFPreferencesFilePath(basePath) {
	return join(sfRoot(basePath), "preferences.yaml");
}
/**
 * Resolve the path to the project-level .sf/runtime/research-decision.json file.
 */
export function researchDecisionPath(basePath) {
	return join(sfRoot(basePath), "runtime", "research-decision.json");
}
/**
 * Write a default research-skip decision marker so deep-mode projects don't
 * prompt for a research step unless the user explicitly opted in.
 *
 * TODO: wire up to a real project-research-policy module when ported.
 */
export function writeDefaultResearchSkipDecision(basePath) {
	const decisionPath = researchDecisionPath(basePath);
	mkdirSync(dirname(decisionPath), { recursive: true });
	const payload = JSON.stringify(
		{ decision: "skip", source: "workflow-preferences" },
		null,
		2,
	);
	writeFileSync(decisionPath, payload, "utf-8");
}
/**
 * Set planning_depth in the project's preferences file (.sf/preferences.yaml).
 * Creates the file if it does not exist. Preserves existing YAML keys.
 * Intended to be called when the user opts into (or out of) deep mode via
 * `/new-project --deep` or similar.
 */
export function setPlanningDepth(basePath, depth) {
	const path = getProjectSFPreferencesFilePath(basePath);
	const { frontmatter } = readProjectPreferencesParts(path);
	frontmatter.planning_depth = depth;
	if (depth === "deep") {
		applyDeepWorkflowPreferenceDefaults(frontmatter);
	}
	writeProjectPreferencesParts(path, frontmatter);
	if (depth === "deep") {
		ensureResearchDecisionDefault(basePath);
	}
}
export function ensureWorkflowPreferencesCaptured(basePath) {
	const path = getProjectSFPreferencesFilePath(basePath);
	const { frontmatter } = readProjectPreferencesParts(path);
	frontmatter.planning_depth = "deep";
	applyDeepWorkflowPreferenceDefaults(frontmatter);
	writeProjectPreferencesParts(path, frontmatter);
	ensureResearchDecisionDefault(basePath);
}
function readProjectPreferencesParts(path) {
	let frontmatter = {};
	if (existsSync(path)) {
		const content = readFileSync(path, "utf-8");
		try {
			const parsed = parseYaml(content);
			if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
				frontmatter = parsed;
			}
		} catch (err) {
			logWarning(
				"guided",
				`preferences.yaml has invalid YAML — rewriting: ${getErrorMessage(err)}`,
			);
		}
	}
	return { frontmatter };
}
function writeProjectPreferencesParts(path, frontmatter) {
	const yamlBlock = stringifyYaml(frontmatter).replace(/\n$/, "");
	mkdirSync(dirname(path), { recursive: true });
	writeFileSync(path, `${yamlBlock}\n`, "utf-8");
}
function applyDeepWorkflowPreferenceDefaults(frontmatter) {
	if (frontmatter.commit_policy === undefined) {
		frontmatter.commit_policy = "per-task";
	}
	if (frontmatter.branch_model === undefined) {
		frontmatter.branch_model = "single";
	}
	if (frontmatter.uat_dispatch === undefined) {
		frontmatter.uat_dispatch = true;
	}
	const existingModels = frontmatter.models;
	const models =
		existingModels &&
		typeof existingModels === "object" &&
		!Array.isArray(existingModels)
			? existingModels
			: {};
	if (models.executor_class === undefined) {
		models.executor_class = "balanced";
	}
	frontmatter.models = models;
	frontmatter.workflow_prefs_captured = true;
}
function ensureResearchDecisionDefault(basePath) {
	const decisionPath = researchDecisionPath(basePath);
	if (existsSync(decisionPath)) {
		try {
			const parsed = JSON.parse(readFileSync(decisionPath, "utf-8"));
			const source =
				typeof parsed.source === "string" ? parsed.source : undefined;
			if (
				parsed.decision === "research" &&
				(source === "research-decision" || source === "user")
			) {
				return;
			}
			if (parsed.decision === "skip" && source !== "workflow-preferences")
				return;
		} catch {
			// Invalid runtime marker is replaced with the default decision.
		}
	}
	writeDefaultResearchSkipDecision(basePath);
}
