import { existsSync, readFileSync } from "node:fs";
import { resolve } from "node:path";
import {
	isAutoActive,
	isAutoPaused,
	pauseAuto,
	startAuto,
	startAutoDetached,
	stopAuto,
	stopAutoRemote,
} from "../../auto.js";
import {
	findUnsupportedAutonomousArgs,
	formatUnsupportedAutonomousArgs,
} from "../../autonomous-command-args.js";
import { handleRate } from "../../commands-rate.js";
import { enableDebug } from "../../debug-logger.js";
import { findMilestoneIds } from "../../milestone-id-utils.js";
import { guardRemoteSession, projectRoot } from "../context.js";

/**
 * Parse --yolo flag and optional file path from the autonomous command string.
 * Supports: `/autonomous --yolo path/to/file.md` or
 * `/autonomous -y path/to/file.md`.
 */
function parseYoloFlag(trimmed) {
	const yoloRe = /(?:--yolo|-y)\s+("(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|\S+)/;
	const match = trimmed.match(yoloRe);
	if (!match) return { yoloSeedFile: null, rest: trimmed };
	// Strip quotes if present
	let filePath = match[1];
	if (
		(filePath.startsWith('"') && filePath.endsWith('"')) ||
		(filePath.startsWith("'") && filePath.endsWith("'"))
	) {
		filePath = filePath.slice(1, -1);
	}
	const rest = trimmed.replace(match[0], "").replace(/\s+/g, " ").trim();
	return { yoloSeedFile: filePath, rest };
}
/**
 * Extract a milestone ID (e.g. M016 or M001-a3b4c5) from the command string.
 * Returns the matched ID and the remaining string with the ID removed.
 * The milestone ID pattern matches the format used by findMilestoneIds: M\d+ with
 * an optional -[a-z0-9]{6} suffix for unique milestone IDs.
 */
export function parseMilestoneTarget(input) {
	const match = input.match(/\b(M\d+(?:-[a-z0-9]{6})?)\b/);
	if (!match) return { milestoneId: null, rest: input };
	const rest = input.replace(match[0], "").replace(/\s+/g, " ").trim();
	return { milestoneId: match[1], rest };
}
/**
 * Dispatch entry point for the autonomous command family.
 *
 * Handles `/autonomous`, `/next`, `/autonomous stop`, `/pause`, and their flag
 * variants.
 * Returns `true` when the command was recognised and routed (caller stops
 * searching), `false` when the command isn't autonomous-related.
 *
 * Recognised flags on autonomous:
 *   - `--verbose`        — verbose execution output
 *   - `--debug`          — enable debug logging via SF_DEBUG
 *   - `M001` (positional) — milestone target lock (only run that milestone)
 *   - `--yolo <file>`     — yolo seed; bootstraps a fresh milestone from a brief
 *
 * The handler validates milestone targets exist, gates remote sessions, then
 * dispatches via `launchAuto` (which routes between machine-surface and detached
 * spawn paths).
 */
export async function handleAutonomousCommand(trimmed, ctx, pi) {
	const isAutonomousVerb =
		trimmed === "autonomous" || trimmed.startsWith("autonomous ");
	/**
	 * Route an autonomous launch through either the machine-surface
	 * (in-process) or detached (spawned subprocess) entry point depending on
	 * `SF_HEADLESS`.
	 *
	 * The machine surface runs the autonomous loop in the current process
	 * (used by CI, tests, and `sf headless`); detached mode forks a long-running
	 * child so the interactive shell stays responsive while autonomous run
	 * control continues.
	 */
	const launchAuto = async (verboseMode, options) => {
		if (process.env.SF_HEADLESS === "1") {
			await startAuto(ctx, pi, projectRoot(), verboseMode, options);
			return;
		}
		startAutoDetached(ctx, pi, projectRoot(), verboseMode, options);
	};
	if (trimmed === "next" || trimmed.startsWith("next ")) {
		if (trimmed.includes("--dry-run")) {
			const { handleDryRun } = await import("../../commands-maintenance.js");
			await handleDryRun(ctx, projectRoot());
			return true;
		}
		const { milestoneId, rest: afterMilestone } = parseMilestoneTarget(trimmed);
		const verboseMode = afterMilestone.includes("--verbose");
		const debugMode = afterMilestone.includes("--debug");
		if (debugMode) enableDebug(projectRoot());
		if (!(await guardRemoteSession(ctx, pi))) return true;
		// Validate the milestone target exists and is not already complete.
		if (milestoneId) {
			const allIds = findMilestoneIds(projectRoot());
			if (!allIds.includes(milestoneId)) {
				ctx.ui.notify(
					`Milestone ${milestoneId} does not exist. Available: ${allIds.join(", ") || "(none)"}`,
					"error",
				);
				return true;
			}
		}
		await launchAuto(verboseMode, {
			step: true,
			milestoneLock: milestoneId,
		});
		return true;
	}
	if (trimmed === "stop") {
		await stopAutonomousRun(ctx, pi);
		return true;
	}
	if (isAutonomousVerb) {
		const autonomousArgsText = trimmed.replace(/^autonomous\b/, "").trim();
		if (autonomousArgsText === "stop") {
			await stopAutonomousRun(ctx, pi);
			return true;
		}
		if (autonomousArgsText === "pause") {
			await pauseAutonomousRun(ctx, pi);
			return true;
		}
		const { yoloSeedFile, rest: afterYolo } = parseYoloFlag(autonomousArgsText);
		const { milestoneId, rest: afterMilestone } =
			parseMilestoneTarget(afterYolo);
		const verboseMode = afterMilestone.includes("--verbose");
		const debugMode = afterMilestone.includes("--debug");
		const canAskUser = false;
		const unsupportedArgs = findUnsupportedAutonomousArgs(
			afterMilestone.split(/\s+/).filter(Boolean),
		);
		if (unsupportedArgs.length > 0) {
			ctx.ui.notify(formatUnsupportedAutonomousArgs(unsupportedArgs), "error");
			return true;
		}
		if (debugMode) enableDebug(projectRoot());
		if (!(await guardRemoteSession(ctx, pi))) return true;
		// Validate the milestone target exists and is not already complete.
		if (milestoneId) {
			const allIds = findMilestoneIds(projectRoot());
			if (!allIds.includes(milestoneId)) {
				ctx.ui.notify(
					`Milestone ${milestoneId} does not exist. Available: ${allIds.join(", ") || "(none)"}`,
					"error",
				);
				return true;
			}
		}
		if (yoloSeedFile) {
			const resolved = resolve(projectRoot(), yoloSeedFile);
			if (!existsSync(resolved)) {
				ctx.ui.notify(`Yolo seed file not found: ${resolved}`, "error");
				return true;
			}
			const seedContent = readFileSync(resolved, "utf-8").trim();
			if (!seedContent) {
				ctx.ui.notify(`Yolo seed file is empty: ${resolved}`, "error");
				return true;
			}
			// Headless path: bootstrap project, dispatch non-interactive discuss,
			// then autonomous mode starts automatically via checkAutoStartAfterDiscuss
			// when the LLM says "Milestone X ready."
			const { showHeadlessMilestoneCreation } = await import(
				"../../guided-flow.js"
			);
			await showHeadlessMilestoneCreation(ctx, pi, projectRoot(), seedContent);
		} else if (milestoneId) {
			await launchAuto(verboseMode, {
				milestoneLock: milestoneId,
				canAskUser,
			});
		} else {
			await launchAuto(verboseMode, { canAskUser });
		}
		return true;
	}
	if (trimmed === "pause") {
		await pauseAutonomousRun(ctx, pi);
		return true;
	}
	if (trimmed === "rate" || trimmed.startsWith("rate ")) {
		await handleRate(
			trimmed.replace(/^rate\s*/, "").trim(),
			ctx,
			projectRoot(),
		);
		return true;
	}
	if (trimmed === "") {
		if (!(await guardRemoteSession(ctx, pi))) return true;
		await launchAuto(false, { step: true });
		return true;
	}
	return false;
}

async function stopAutonomousRun(ctx, pi) {
	if (!isAutoActive() && !isAutoPaused()) {
		const result = stopAutoRemote(projectRoot());
		if (result.found) {
			ctx.ui.notify(
				`Sent stop signal to autonomous mode session (PID ${result.pid}). It will shut down gracefully.`,
				"info",
			);
		} else if (result.error) {
			ctx.ui.notify(
				`Failed to stop remote autonomous run: ${result.error}`,
				"error",
			);
		} else {
			ctx.ui.notify("Autonomous mode is not running.", "info");
		}
		return;
	}
	await stopAuto(ctx, pi, "User requested stop");
}

async function pauseAutonomousRun(ctx, pi) {
	if (!isAutoActive()) {
		if (isAutoPaused()) {
			ctx.ui.notify(
				"Autonomous mode is already paused. /autonomous to resume.",
				"info",
			);
		} else {
			ctx.ui.notify("Autonomous mode is not running.", "info");
		}
		return;
	}
	await pauseAuto(ctx, pi);
}
