/**
 * SF Rethink — Conversational project reorganization.
 *
 * Collects a snapshot of all milestones (status, dependencies, slice progress,
 * queue order) and dispatches a prompt that turns Claude into a reorganization
 * assistant. Claude can then reorder, park, unpark, discard, or add milestones
 * through conversation.
 */
import { existsSync } from "node:fs";
import { isAutoActive } from "./auto.js";
import { isSfGitignored } from "./gitignore.js";
import { buildExistingMilestonesContext } from "./guided-flow-queue.js";
import { getParkedReason } from "./milestone-actions.js";
import { findMilestoneIds } from "./milestone-ids.js";
import { sfRoot } from "./paths.js";
import { loadPrompt } from "./prompt-loader.js";
import { loadQueueOrder, validateQueueOrder } from "./queue-order.js";
import { getMilestoneSlices, isDbAvailable } from "./sf-db.js";
import { deriveState } from "./state.js";
// ─── Entry Point ──────────────────────────────────────────────────────────────
export async function handleRethink(_args, ctx, pi) {
	if (isAutoActive()) {
		ctx.ui.notify(
			"Cannot rethink while autonomous mode is active. Stop autonomous mode first.",
			"error",
		);
		return;
	}
	const basePath = process.cwd();
	const root = sfRoot(basePath);
	if (!existsSync(root)) {
		ctx.ui.notify("No SF project found. Run /init first.", "warning");
		return;
	}
	ctx.ui.notify("Building project snapshot for rethink...", "info");
	const state = await deriveState(basePath);
	const milestoneIds = findMilestoneIds(basePath);
	if (milestoneIds.length === 0) {
		ctx.ui.notify("No milestones exist yet. Nothing to rethink.", "warning");
		return;
	}
	const queueOrder = loadQueueOrder(basePath);
	const rethinkData = buildRethinkData(
		basePath,
		milestoneIds,
		state,
		queueOrder,
	);
	const existingMilestonesContext = await buildExistingMilestonesContext(
		basePath,
		milestoneIds,
		state,
	);
	const commitInstruction = isSfGitignored(basePath)
		? "Do not commit planning artifacts — .sf/ is gitignored in this project."
		: 'After changes, run `git add .sf/ && git commit -m "docs(sf): rethink milestone plan"` to persist (rethink runs interactively outside autonomous mode, so no system auto-commit)';
	const content = loadPrompt("rethink", {
		rethinkData,
		existingMilestonesContext,
		commitInstruction,
	});
	pi.sendMessage(
		{ customType: "sf-rethink", content, display: false },
		{ triggerTurn: true },
	);
}
// ─── Data Builder ─────────────────────────────────────────────────────────────
function buildRethinkData(basePath, milestoneIds, state, queueOrder) {
	const lines = [];
	const dbAvailable = isDbAvailable();
	// ── Summary stats ───────────────────────────────────────────────────
	const counts = { complete: 0, active: 0, pending: 0, parked: 0 };
	for (const entry of state.registry) {
		if (entry.status in counts) counts[entry.status]++;
	}
	lines.push("### Summary");
	lines.push(
		`${counts.complete} complete, ${counts.active} active, ${counts.pending} pending, ${counts.parked} parked — ${milestoneIds.length} total`,
	);
	lines.push(
		`Queue order source: ${queueOrder ? "SQLite milestone sequence" : "default numeric (by ID)"}`,
	);
	if (state.activeMilestone) {
		lines.push(`Active milestone: ${state.activeMilestone}`);
	}
	lines.push("");
	// ── Milestone table ─────────────────────────────────────────────────
	lines.push("### Execution Order");
	lines.push("");
	lines.push("| # | ID | Title | Status | Dependencies | Slices |");
	lines.push("|---|-----|-------|--------|--------------|--------|");
	for (let i = 0; i < milestoneIds.length; i++) {
		const mid = milestoneIds[i];
		const entry = state.registry.find((m) => m.id === mid);
		const title = entry?.title ?? mid;
		const status = entry?.status ?? "unknown";
		const deps = entry?.dependsOn?.length ? entry.dependsOn.join(", ") : "—";
		let sliceInfo = "—";
		if (dbAvailable && status !== "complete") {
			const slices = getMilestoneSlices(mid);
			if (slices.length > 0) {
				const done = slices.filter(
					(s) => s.status === "complete" || s.status === "done",
				).length;
				const skipped = slices.filter((s) => s.status === "skipped").length;
				sliceInfo =
					skipped > 0
						? `${done}/${slices.length} complete, ${skipped} skipped`
						: `${done}/${slices.length} complete`;
			}
		}
		// Add parked reason if applicable
		let statusDisplay = status;
		if (status === "parked") {
			const reason = getParkedReason(basePath, mid);
			if (reason) statusDisplay = `parked (${reason})`;
		}
		lines.push(
			`| ${i + 1} | ${mid} | ${title} | ${statusDisplay} | ${deps} | ${sliceInfo} |`,
		);
	}
	// ── Dependency validation ───────────────────────────────────────────
	const pendingIds = milestoneIds.filter((mid) => {
		const entry = state.registry.find((m) => m.id === mid);
		return entry?.status !== "complete";
	});
	const completedIds = new Set(
		state.registry.filter((m) => m.status === "complete").map((m) => m.id),
	);
	const depsMap = new Map();
	for (const entry of state.registry) {
		if (entry.dependsOn?.length) {
			depsMap.set(entry.id, entry.dependsOn);
		}
	}
	if (pendingIds.length > 0 && depsMap.size > 0) {
		const validation = validateQueueOrder(pendingIds, depsMap, completedIds);
		if (validation.violations.length > 0) {
			lines.push("");
			lines.push("### Dependency Issues");
			for (const v of validation.violations) {
				lines.push(`- **${v.type}**: ${v.message}`);
			}
		}
	}
	return lines.join("\n");
}
