/**
 * experimental.js — Feature flag helpers for SF experimental features.
 *
 * Purpose: single read/write surface for prefs.experimental flags so that
 * every gated feature calls getExperimentalFlag(name) rather than reaching
 * into preferences directly.
 *
 * Consumer: /experimental command handler, all features gated by flags.
 */

import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { dirname } from "node:path";
import { serializePreferencesToFrontmatter } from "./commands-prefs-wizard.js";
import {
	getProjectSFPreferencesPath,
	loadEffectiveSFPreferences,
	loadProjectSFPreferences,
} from "./preferences.js";

/** Extract the body section that follows a YAML frontmatter block. */
function extractBodyAfterFrontmatter(content) {
	const closingIdx = content.indexOf("\n---", content.indexOf("---"));
	if (closingIdx === -1) return null;
	const afterFrontmatter = content.slice(closingIdx + 4);
	return afterFrontmatter.trim() ? afterFrontmatter : null;
}

/** All recognized experimental feature flags with descriptions. */
export const EXPERIMENTAL_FLAGS = {
	status_line:
		"STATUS_LINE — run a user-defined script to feed a custom footer status chip",
	show_file:
		"SHOW_FILE — show_file tool renders code snippets inline in the timeline",
	extensions:
		"EXTENSIONS — user-installable extensions via marketplace npm install",
	configure_agent:
		"CONFIGURE_COPILOT_AGENT — interactive wizard for MCP servers and agents",
	background_sessions:
		"BACKGROUND_SESSIONS — concurrent sessions with background switching",
	prompt_frame:
		"PROMPT_FRAME — decorative border rendered above the input prompt",
	smoke_gate:
		"SMOKE_GATE — write last-green ledger entry after successful smoke fixture dispatch; suppresses writes when false for crash-loop rollback in S04",
};

/**
 * Read a single experimental flag from the effective (merged) preferences.
 * Returns true only when the flag is explicitly set to true.
 *
 * Purpose: cheap, consistent read path for all feature-gated code paths.
 * Consumer: every feature behind an experimental flag.
 */
export function getExperimentalFlag(name) {
	const prefs = loadEffectiveSFPreferences();
	return prefs?.preferences?.experimental?.[name] === true;
}

/**
 * Read all experimental flags from the effective preferences.
 *
 * Purpose: /experimental show lists every flag and its current state.
 * Consumer: handleExperimentalCommand (show sub-command).
 */
export function getAllExperimentalFlags() {
	const prefs = loadEffectiveSFPreferences();
	return prefs?.preferences?.experimental ?? {};
}

/**
 * Write a single experimental flag to the project preferences file.
 * Creates the file if it does not exist. Preserves all other fields.
 *
 * Purpose: /experimental on <flag> / off <flag> writes back cleanly.
 * Consumer: handleExperimentalCommand.
 */
export function setExperimentalFlag(name, value) {
	const path = getProjectSFPreferencesPath();
	const existing = loadProjectSFPreferences();
	const prefs = existing?.preferences ? { ...existing.preferences } : {};
	prefs.version = prefs.version || 1;
	prefs.experimental = { ...(prefs.experimental ?? {}), [name]: value };

	const frontmatter = serializePreferencesToFrontmatter(prefs);
	let body =
		"\n# SF Preferences\n\nSee `~/.sf/agent/extensions/sf/docs/preferences-reference.md` for full documentation.\n";
	if (existsSync(path)) {
		const preserved = extractBodyAfterFrontmatter(readFileSync(path, "utf-8"));
		if (preserved) body = preserved;
	}
	mkdirSync(dirname(path), { recursive: true });
	writeFileSync(path, `---\n${frontmatter}---${body}`, "utf-8");
}

/**
 * Enable or disable all known experimental flags in one call.
 *
 * Purpose: /experimental on (no flag arg) bulk-enables all flags.
 * Consumer: handleExperimentalCommand bulk toggle.
 */
export function setAllExperimentalFlags(value) {
	for (const name of Object.keys(EXPERIMENTAL_FLAGS)) {
		setExperimentalFlag(name, value);
	}
}
