/**
 * Direct phase dispatch — handles manual /dispatch commands.
 * Resolves phase name → unit type + prompt, creates a session, and sends the message.
 */
import { pauseAuto } from "./auto.js";
import {
	buildCompleteMilestonePrompt,
	buildCompleteSlicePrompt,
	buildExecuteTaskPrompt,
	buildPlanMilestonePrompt,
	buildPlanSlicePrompt,
	buildReassessRoadmapPrompt,
	buildReplanSlicePrompt,
	buildResearchMilestonePrompt,
	buildResearchSlicePrompt,
	buildRunUatPrompt,
} from "./auto-prompts.js";
import { scopeActiveToolsForUnitType } from "./constants.js";
import { loadFile } from "./files.js";
import { relSliceFile, resolveSliceFile } from "./paths.js";
import { loadEffectiveSFPreferences } from "./preferences.js";
import { getMilestoneSlices, isDbAvailable } from "./sf-db.js";
import { deriveState } from "./state.js";
import {
	getRequiredWorkflowToolsForAutoUnit,
	getWorkflowTransportSupportError,
} from "./workflow-tools.js";
export async function dispatchDirectPhase(ctx, pi, phase, base) {
	const state = await deriveState(base);
	const mid = state.activeMilestone?.id;
	const midTitle = state.activeMilestone?.title ?? "";
	if (!mid) {
		ctx.ui.notify("Cannot dispatch: no active milestone.", "warning");
		return;
	}
	const normalized = phase.toLowerCase();
	let unitType;
	let unitId;
	let prompt;
	switch (normalized) {
		case "research":
		case "research-milestone":
		case "research-slice": {
			const isSlice =
				normalized === "research-slice" ||
				(normalized === "research" && state.phase !== "pre-planning");
			if (isSlice) {
				const sid = state.activeSlice?.id;
				const sTitle = state.activeSlice?.title ?? "";
				if (!sid) {
					ctx.ui.notify(
						"Cannot dispatch research-slice: no active slice.",
						"warning",
					);
					return;
				}
				// When require_slice_discussion is enabled, pause autonomous mode before
				// each new slice so the user can discuss requirements first (#789).
				const sliceContextFile = resolveSliceFile(base, mid, sid, "CONTEXT");
				const requireDiscussion =
					loadEffectiveSFPreferences()?.preferences?.phases
						?.require_slice_discussion;
				if (requireDiscussion && !sliceContextFile) {
					ctx.ui.notify(
						`Slice ${sid} requires discussion before planning. Run /discuss to discuss this slice, then /autonomous to resume.`,
						"info",
					);
					await pauseAuto(ctx, pi);
					return;
				}
				unitType = "research-slice";
				unitId = `${mid}/${sid}`;
				prompt = await buildResearchSlicePrompt(
					mid,
					midTitle,
					sid,
					sTitle,
					base,
				);
			} else {
				unitType = "research-milestone";
				unitId = mid;
				prompt = await buildResearchMilestonePrompt(mid, midTitle, base);
			}
			break;
		}
		case "plan":
		case "plan-milestone":
		case "plan-slice": {
			const isSlice =
				normalized === "plan-slice" ||
				(normalized === "plan" && state.phase !== "pre-planning");
			if (isSlice) {
				const sid = state.activeSlice?.id;
				const sTitle = state.activeSlice?.title ?? "";
				if (!sid) {
					ctx.ui.notify(
						"Cannot dispatch plan-slice: no active slice.",
						"warning",
					);
					return;
				}
				unitType = "plan-slice";
				unitId = `${mid}/${sid}`;
				prompt = await buildPlanSlicePrompt(mid, midTitle, sid, sTitle, base);
			} else {
				unitType = "plan-milestone";
				unitId = mid;
				prompt = await buildPlanMilestonePrompt(mid, midTitle, base);
			}
			break;
		}
		case "execute":
		case "execute-task": {
			const sid = state.activeSlice?.id;
			const sTitle = state.activeSlice?.title ?? "";
			const tid = state.activeTask?.id;
			const tTitle = state.activeTask?.title ?? "";
			if (!sid) {
				ctx.ui.notify(
					"Cannot dispatch execute-task: no active slice.",
					"warning",
				);
				return;
			}
			if (!tid) {
				ctx.ui.notify(
					"Cannot dispatch execute-task: no active task.",
					"warning",
				);
				return;
			}
			unitType = "execute-task";
			unitId = `${mid}/${sid}/${tid}`;
			prompt = await buildExecuteTaskPrompt(
				mid,
				sid,
				sTitle,
				tid,
				tTitle,
				base,
			);
			break;
		}
		case "complete":
		case "complete-slice":
		case "complete-milestone": {
			const isSlice =
				normalized === "complete-slice" ||
				(normalized === "complete" && state.phase === "summarizing");
			if (isSlice) {
				const sid = state.activeSlice?.id;
				const sTitle = state.activeSlice?.title ?? "";
				if (!sid) {
					ctx.ui.notify(
						"Cannot dispatch complete-slice: no active slice.",
						"warning",
					);
					return;
				}
				unitType = "complete-slice";
				unitId = `${mid}/${sid}`;
				prompt = await buildCompleteSlicePrompt(
					mid,
					midTitle,
					sid,
					sTitle,
					base,
				);
			} else {
				unitType = "complete-milestone";
				unitId = mid;
				prompt = await buildCompleteMilestonePrompt(mid, midTitle, base);
			}
			break;
		}
		case "reassess":
		case "reassess-roadmap": {
			let completedSliceIds = [];
			if (isDbAvailable()) {
				completedSliceIds = getMilestoneSlices(mid)
					.filter((s) => s.status === "complete")
					.map((s) => s.id);
			} else {
				ctx.ui.notify(
					"Cannot dispatch reassess-roadmap: database unavailable.",
					"warning",
				);
				return;
			}
			if (completedSliceIds.length === 0) {
				ctx.ui.notify(
					"Cannot dispatch reassess-roadmap: no completed slices.",
					"warning",
				);
				return;
			}
			const completedSliceId = completedSliceIds[completedSliceIds.length - 1];
			unitType = "reassess-roadmap";
			unitId = `${mid}/${completedSliceId}`;
			prompt = await buildReassessRoadmapPrompt(
				mid,
				midTitle,
				completedSliceId,
				base,
			);
			break;
		}
		case "uat":
		case "run-uat": {
			// UAT targets the most recently completed slice, not the active (next
			// incomplete) slice. After slice completion, state.activeSlice advances
			// to the next incomplete slice, so we find the last done slice from the
			// DB instead (#1693).
			let uatCompletedSliceIds = [];
			if (isDbAvailable()) {
				uatCompletedSliceIds = getMilestoneSlices(mid)
					.filter((s) => s.status === "complete")
					.map((s) => s.id);
			} else {
				ctx.ui.notify(
					"Cannot dispatch run-uat: database unavailable.",
					"warning",
				);
				return;
			}
			if (uatCompletedSliceIds.length === 0) {
				ctx.ui.notify(
					"Cannot dispatch run-uat: no completed slices.",
					"warning",
				);
				return;
			}
			const sid = uatCompletedSliceIds[uatCompletedSliceIds.length - 1];
			const uatFile = resolveSliceFile(base, mid, sid, "UAT");
			if (!uatFile) {
				ctx.ui.notify("Cannot dispatch run-uat: no UAT file found.", "warning");
				return;
			}
			const uatContent = await loadFile(uatFile);
			if (!uatContent) {
				ctx.ui.notify("Cannot dispatch run-uat: UAT file is empty.", "warning");
				return;
			}
			const uatPath = relSliceFile(base, mid, sid, "UAT");
			unitType = "run-uat";
			unitId = `${mid}/${sid}`;
			prompt = await buildRunUatPrompt(mid, sid, uatPath, uatContent, base);
			break;
		}
		case "replan":
		case "replan-slice": {
			const sid = state.activeSlice?.id;
			const sTitle = state.activeSlice?.title ?? "";
			if (!sid) {
				ctx.ui.notify(
					"Cannot dispatch replan-slice: no active slice.",
					"warning",
				);
				return;
			}
			unitType = "replan-slice";
			unitId = `${mid}/${sid}`;
			prompt = await buildReplanSlicePrompt(mid, midTitle, sid, sTitle, base);
			break;
		}
		default:
			ctx.ui.notify(
				`Unknown phase "${phase}". Valid phases: research, plan, execute, complete, reassess, uat, replan.`,
				"warning",
			);
			return;
	}
	const compatibilityError = getWorkflowTransportSupportError(
		ctx.model?.provider,
		getRequiredWorkflowToolsForAutoUnit(unitType),
		{
			projectRoot: base,
			surface: "direct phase dispatch",
			unitType,
			authMode: ctx.model?.provider
				? ctx.modelRegistry.getProviderAuthMode(ctx.model.provider)
				: undefined,
			baseUrl: ctx.model?.baseUrl,
		},
	);
	if (compatibilityError) {
		ctx.ui.notify(compatibilityError, "error");
		return;
	}
	ctx.ui.notify(`Dispatching ${unitType} for ${unitId}...`, "info");
	const result = await ctx.newSession();
	if (result.cancelled) {
		ctx.ui.notify("Session creation cancelled.", "warning");
		return;
	}
	let savedTools = null;
	if (
		typeof pi.getActiveTools === "function" &&
		typeof pi.setActiveTools === "function"
	) {
		const currentTools = pi.getActiveTools();
		const scopedTools = scopeActiveToolsForUnitType(unitType, currentTools);
		if (scopedTools.length !== currentTools.length) {
			savedTools = currentTools;
			pi.setActiveTools(scopedTools);
		}
	}
	try {
		await pi.sendMessage(
			{ customType: "sf-dispatch", content: prompt, display: false },
			{ triggerTurn: true },
		);
	} finally {
		if (savedTools) pi.setActiveTools(savedTools);
	}
}
