/**
 * SF Quick Mode — /quick <task>
 * Copyright (c) 2026 Jeremy McSpadden <jeremy@fluxlabs.net>
 *
 * Lightweight task execution with SF guarantees (atomic commits, state
 * tracking) but without the full milestone/slice ceremony.
 *
 * Quick tasks live in `.sf/quick/` and are tracked in STATE.md's
 * "Quick Tasks Completed" table.
 */
import {
	existsSync,
	mkdirSync,
	readdirSync,
	readFileSync,
	rmSync,
	writeFileSync,
} from "node:fs";
import { join } from "node:path";
import { getErrorMessage } from "./error-utils.js";
import { GitService, runGit } from "./git-service.js";
import { nativeHasStagedChanges } from "./native-git-bridge.js";
import { sfRoot } from "./paths.js";
import { loadEffectiveSFPreferences } from "./preferences.js";
import { loadPrompt } from "./prompt-loader.js";

let pendingQuickReturn = null;
// ─── Quick Task Helpers ───────────────────────────────────────────────────────
/**
 * Generate a URL-friendly slug from a description.
 * Lowercase, hyphens, max 40 chars.
 */
function slugify(text) {
	return text
		.toLowerCase()
		.replace(/[^a-z0-9]+/g, "-")
		.replace(/^-|-$/g, "")
		.slice(0, 40)
		.replace(/-$/, "");
}
/**
 * Determine the next quick task number by scanning existing directories.
 */
function getNextTaskNum(quickDir) {
	if (!existsSync(quickDir)) return 1;
	try {
		const entries = readdirSync(quickDir, { withFileTypes: true });
		let max = 0;
		for (const entry of entries) {
			if (!entry.isDirectory()) continue;
			const match = entry.name.match(/^(\d+)-/);
			if (match) {
				const num = parseInt(match[1], 10);
				if (num > max) max = num;
			}
		}
		return max + 1;
	} catch {
		return 1;
	}
}
/**
 * Ensure the quick task directory structure exists.
 * Returns the task directory path.
 */
function ensureQuickDir(basePath, taskNum, slug) {
	const quickDir = join(sfRoot(basePath), "quick");
	const taskDir = join(quickDir, `${taskNum}-${slug}`);
	mkdirSync(taskDir, { recursive: true });
	return taskDir;
}
function quickReturnStatePath(basePath) {
	return join(sfRoot(basePath), "runtime", "quick-return.json");
}
function persistPendingReturn(state) {
	pendingQuickReturn = state;
	mkdirSync(join(sfRoot(state.basePath), "runtime"), { recursive: true });
	writeFileSync(
		quickReturnStatePath(state.basePath),
		JSON.stringify(state) + "\n",
		"utf-8",
	);
}
function readPendingReturn(basePath) {
	if (pendingQuickReturn && pendingQuickReturn.basePath === basePath) {
		return pendingQuickReturn;
	}
	try {
		const raw = readFileSync(quickReturnStatePath(basePath), "utf-8");
		const parsed = JSON.parse(raw);
		if (
			typeof parsed.basePath === "string" &&
			typeof parsed.originalBranch === "string" &&
			typeof parsed.quickBranch === "string" &&
			typeof parsed.taskNum === "number" &&
			typeof parsed.slug === "string" &&
			typeof parsed.description === "string"
		) {
			pendingQuickReturn = parsed;
			return pendingQuickReturn;
		}
	} catch {
		// No persisted quick-return state
	}
	return null;
}
function clearPendingReturn(basePath) {
	if (pendingQuickReturn?.basePath === basePath) {
		pendingQuickReturn = null;
	}
	rmSync(quickReturnStatePath(basePath), { force: true });
}
function hasStagedChanges(basePath) {
	return nativeHasStagedChanges(basePath);
}
export function cleanupQuickBranch(basePath = process.cwd()) {
	const state = readPendingReturn(basePath);
	if (!state) return false;
	const repoPath = state.basePath;
	const gitPrefs = loadEffectiveSFPreferences()?.preferences?.git ?? {};
	const git = new GitService(repoPath, gitPrefs);
	if (git.getCurrentBranch() === state.quickBranch) {
		try {
			git.autoCommit("quick-task", `Q${state.taskNum}`, []);
		} catch {
			// Best-effort: quick work may already be committed.
		}
	}
	if (git.getCurrentBranch() !== state.originalBranch) {
		runGit(repoPath, ["checkout", state.originalBranch]);
	}
	runGit(repoPath, ["merge", "--squash", state.quickBranch]);
	if (hasStagedChanges(repoPath)) {
		runGit(repoPath, [
			"commit",
			"-m",
			`quick(Q${state.taskNum}): ${state.slug}`,
		]);
	}
	runGit(repoPath, ["branch", "-D", state.quickBranch], { allowFailure: true });
	clearPendingReturn(repoPath);
	return true;
}
// ─── Main Handler ─────────────────────────────────────────────────────────────
export async function handleQuick(args, ctx, pi) {
	const basePath = process.cwd();
	const root = sfRoot(basePath);
	// Validate: .sf/ must exist
	if (!existsSync(root)) {
		ctx.ui.notify(
			"No .sf/ directory found. Run /init to initialize a project first.",
			"error",
		);
		return;
	}
	// Parse description from args
	const description = args.trim();
	if (!description) {
		ctx.ui.notify(
			"Usage: /quick <task description>\n\nExample: /quick fix login button not responding on mobile",
			"info",
		);
		return;
	}
	// Setup
	const quickDir = join(root, "quick");
	const taskNum = getNextTaskNum(quickDir);
	const slug = slugify(description);
	const _taskDir = ensureQuickDir(basePath, taskNum, slug);
	const taskDirRel = `.sf/quick/${taskNum}-${slug}`;
	const date = new Date().toISOString().split("T")[0];
	// Create git branch for the quick task (unless isolation:none — #3337)
	const gitPrefs = loadEffectiveSFPreferences()?.preferences?.git ?? {};
	const git = new GitService(basePath, gitPrefs);
	const branchName = `sf/quick/${taskNum}-${slug}`;
	const originalBranch = git.getCurrentBranch();
	const { getIsolationMode } = await import("./preferences.js");
	const usesBranch = getIsolationMode() !== "none";
	let branchCreated = false;
	if (usesBranch) {
		try {
			const current = originalBranch;
			if (current !== branchName) {
				// Auto-commit any dirty state before switching
				try {
					git.autoCommit("quick-task", `Q${taskNum}`, []);
				} catch {
					/* nothing to commit — fine */
				}
				runGit(basePath, ["checkout", "-b", branchName]);
				branchCreated = true;
			}
		} catch (err) {
			// Branch creation failed — continue on current branch
			const message = getErrorMessage(err);
			ctx.ui.notify(
				`Could not create branch ${branchName}: ${message}. Working on current branch.`,
				"warning",
			);
		}
	}
	const actualBranch = branchCreated ? branchName : git.getCurrentBranch();
	if (actualBranch === branchName && originalBranch !== branchName) {
		persistPendingReturn({
			basePath,
			originalBranch,
			quickBranch: branchName,
			taskNum,
			slug,
			description,
		});
	}
	// Notify user
	ctx.ui.notify(
		`Quick task ${taskNum}: ${description}\nDirectory: ${taskDirRel}\nBranch: ${actualBranch}`,
		"info",
	);
	// Build and dispatch the quick task prompt
	const summaryPath = `${taskDirRel}/${taskNum}-SUMMARY.md`;
	const prompt = loadPrompt("quick-task", {
		description,
		taskDir: taskDirRel,
		branch: actualBranch,
		summaryPath,
		date,
		taskNum: String(taskNum),
		slug,
	});
	pi.sendMessage(
		{
			customType: "sf-quick-task",
			content: prompt,
			display: false,
		},
		{ triggerTurn: true },
	);
}
