/**
 * SF Command — /scan
 *
 * Rapid codebase assessment — lightweight alternative to /map-codebase.
 * Spawns one focused AI analysis pass and writes structured documents to
 * .sf/codebase/ for use by planning and execution phases.
 *
 * Usage:
 *   /scan                   — tech+arch focus (default)
 *   /scan --focus tech      — technology stack + integrations only
 *   /scan --focus arch      — architecture + structure only
 *   /scan --focus quality   — conventions + testing patterns only
 *   /scan --focus concerns  — technical debt + concerns only
 *   /scan --focus tech+arch — explicit default (same as no flag)
 */
import { existsSync, mkdirSync } from "node:fs";
import { join, relative } from "node:path";
import { getErrorMessage } from "./error-utils.js";
import { loadPrompt } from "./prompt-loader.js";
// ─── Constants ────────────────────────────────────────────────────────────────
export const DEFAULT_FOCUS = "tech+arch";
export const VALID_FOCUS_AREAS = [
	"tech",
	"arch",
	"quality",
	"concerns",
	"tech+arch",
];
const FOCUS_DOCUMENTS = {
	tech: ["STACK", "INTEGRATIONS"],
	arch: ["ARCHITECTURE", "STRUCTURE"],
	quality: ["CONVENTIONS", "TESTING"],
	concerns: ["CONCERNS"],
	"tech+arch": ["STACK", "INTEGRATIONS", "ARCHITECTURE", "STRUCTURE"],
};
// ─── Exported functions (exported for testing) ───────────────────────────────
/**
 * Parse --focus flag from raw args string.
 * Returns default focus when flag is missing or the value is invalid.
 * Shell-injection safe: only well-known values are accepted.
 */
export function parseScanArgs(args) {
	const match = args.match(/--focus\s+([^\s]+)/i);
	if (!match) return { focus: DEFAULT_FOCUS };
	const raw = match[1].toLowerCase();
	if (VALID_FOCUS_AREAS.includes(raw)) {
		return { focus: raw };
	}
	return { focus: DEFAULT_FOCUS };
}
/**
 * Return the list of document names (without extension) to generate for a focus.
 * Falls back to the default focus documents for unknown values.
 */
export function resolveScanDocuments(focus) {
	return FOCUS_DOCUMENTS[focus] ?? FOCUS_DOCUMENTS[DEFAULT_FOCUS];
}
/**
 * Build absolute output paths for the documents produced by a scan focus.
 * All documents live under <basePath>/.sf/codebase/
 */
export function buildScanOutputPaths(focus, basePath) {
	const docs = resolveScanDocuments(focus);
	return docs.map((doc) => join(basePath, ".sf", "codebase", `${doc}.md`));
}
/**
 * Return the subset of paths that already exist on disk.
 */
export function checkExistingDocuments(paths) {
	return paths.filter((p) => existsSync(p));
}
// ─── Command handler ──────────────────────────────────────────────────────────
export async function handleScan(args, ctx, pi) {
	const basePath = process.cwd();
	const { focus } = parseScanArgs(args);
	const outputDir = join(basePath, ".sf", "codebase");
	const outputPaths = buildScanOutputPaths(focus, basePath);
	const existing = checkExistingDocuments(outputPaths);
	if (existing.length > 0) {
		const names = existing.map((p) => relative(outputDir, p)).join(", ");
		ctx.ui.notify(
			`Existing documents will be overwritten: ${names}\nContinuing scan with focus: ${focus}`,
			"warning",
		);
	}
	mkdirSync(outputDir, { recursive: true });
	const documents = resolveScanDocuments(focus);
	ctx.ui.notify(`Running codebase scan (focus: ${focus})…`, "info");
	try {
		const prompt = loadPrompt("scan", {
			focus,
			documents: documents.join(", "),
			outputDir: outputDir.replaceAll("\\", "/"),
			workingDirectory: basePath,
		});
		pi.sendMessage(
			{ customType: "sf-scan", content: prompt, display: false },
			{ triggerTurn: true },
		);
	} catch (err) {
		const msg = getErrorMessage(err);
		ctx.ui.notify(`Failed to dispatch scan: ${msg}`, "error");
	}
}
