import { loadFile } from "./files.js";
import { findMilestoneIds } from "./guided-flow.js";
import { parsePlan, parseRoadmap } from "./parsers.js";
import {
	resolveMilestoneFile,
	resolveSliceFile,
	resolveTaskFile,
	resolveTasksDir,
} from "./paths.js";
import {
	getMilestoneSlices,
	getMilestoneValidationAssessment,
	getSliceTasks,
	isDbAvailable,
} from "./sf-db.js";
import { deriveState } from "./state.js";
import { detectWorktreeName, getSliceBranchName } from "./worktree.js";

// Extract milestone title from roadmap header without using parsers.
// Falls back to the milestone ID if no title line found.
function titleFromRoadmapHeader(content, fallbackId) {
	// Parse the "# M001: Title" header directly
	const match = content.match(/^#\s+M\d+(?:-[a-z0-9]{6})?[^:]*:\s*(.+)/m);
	return match?.[1]?.trim() || fallbackId;
}
async function indexSlice(
	basePath,
	milestoneId,
	sliceId,
	fallbackTitle,
	done,
	roadmapMeta,
) {
	const planPath =
		resolveSliceFile(basePath, milestoneId, sliceId, "PLAN") ?? undefined;
	const summaryPath =
		resolveSliceFile(basePath, milestoneId, sliceId, "SUMMARY") ?? undefined;
	const uatPath =
		resolveSliceFile(basePath, milestoneId, sliceId, "UAT") ?? undefined;
	const tasksDir = resolveTasksDir(basePath, milestoneId, sliceId) ?? undefined;
	const tasks = [];
	let title = fallbackTitle;
	// Prefer DB for task data, fall back to file parsing when DB has no data
	let usedDb = false;
	if (isDbAvailable()) {
		const dbTasks = getSliceTasks(milestoneId, sliceId);
		if (dbTasks.length > 0) {
			usedDb = true;
			for (const task of dbTasks) {
				title = fallbackTitle; // title comes from slice-level data, not plan
				tasks.push({
					id: task.id,
					title: task.title,
					done: task.status === "complete" || task.status === "done",
					planPath:
						resolveTaskFile(basePath, milestoneId, sliceId, task.id, "PLAN") ??
						undefined,
					summaryPath:
						resolveTaskFile(
							basePath,
							milestoneId,
							sliceId,
							task.id,
							"SUMMARY",
						) ?? undefined,
				});
			}
		}
	}
	if (!usedDb && planPath) {
		// File-based fallback: parse slice plan for task entries
		const planContent = await loadFile(planPath);
		if (planContent) {
			const parsed = parsePlan(planContent);
			for (const task of parsed.tasks) {
				tasks.push({
					id: task.id,
					title: task.title,
					done: task.done,
					planPath:
						resolveTaskFile(basePath, milestoneId, sliceId, task.id, "PLAN") ??
						undefined,
					summaryPath:
						resolveTaskFile(
							basePath,
							milestoneId,
							sliceId,
							task.id,
							"SUMMARY",
						) ?? undefined,
				});
			}
		}
	}
	return {
		id: sliceId,
		title,
		done,
		planPath,
		summaryPath,
		uatPath,
		tasksDir,
		branch: getSliceBranchName(
			milestoneId,
			sliceId,
			detectWorktreeName(basePath),
		),
		risk: roadmapMeta?.risk,
		depends: roadmapMeta?.depends,
		demo: roadmapMeta?.demo,
		tasks,
	};
}
export async function indexWorkspace(basePath, _opts = {}) {
	const milestoneIds = findMilestoneIds(basePath);
	const milestones = [];
	for (const milestoneId of milestoneIds) {
		const roadmapPath =
			resolveMilestoneFile(basePath, milestoneId, "ROADMAP") ?? undefined;
		let title = milestoneId;
		const slices = [];
		if (roadmapPath || isDbAvailable()) {
			let normSlices = null;
			if (isDbAvailable()) {
				const dbSlices = getMilestoneSlices(milestoneId);
				if (dbSlices.length > 0) {
					normSlices = dbSlices.map((s) => ({
						id: s.id,
						done: s.status === "complete",
						title: s.title,
						risk: s.risk || "medium",
						depends: s.depends,
						demo: s.demo,
					}));
				}
				// Get title from roadmap header
				if (roadmapPath) {
					const roadmapContent = await loadFile(roadmapPath);
					if (roadmapContent)
						title = titleFromRoadmapHeader(roadmapContent, milestoneId);
				}
			}
			if (!normSlices && roadmapPath) {
				// File-based fallback: parse roadmap for slice entries
				const roadmapContent = await loadFile(roadmapPath);
				if (roadmapContent) {
					title = titleFromRoadmapHeader(roadmapContent, milestoneId);
					const parsed = parseRoadmap(roadmapContent);
					normSlices = parsed.slices.map((s) => ({
						id: s.id,
						done: s.done,
						title: s.title,
						risk: s.risk || "medium",
						depends: s.depends,
						demo: s.demo || "",
					}));
				}
			}
			if (!normSlices) normSlices = [];
			if (normSlices.length > 0) {
				const sliceResults = await Promise.all(
					normSlices.map(async (slice) => {
						return indexSlice(
							basePath,
							milestoneId,
							slice.id,
							slice.title,
							slice.done,
							{
								risk: slice.risk,
								depends: slice.depends,
								demo: slice.demo,
							},
						);
					}),
				);
				slices.push(...sliceResults);
			}
		}
		milestones.push({ id: milestoneId, title, roadmapPath, slices });
	}
	const state = await deriveState(basePath);
	const active = {
		milestoneId: state.activeMilestone?.id,
		sliceId: state.activeSlice?.id,
		taskId: state.activeTask?.id,
		phase: state.phase,
	};
	// Enrich milestones with authoritative status from state registry (#2807)
	if (state.registry) {
		const registryMap = new Map(state.registry.map((e) => [e.id, e]));
		for (const milestone of milestones) {
			const entry = registryMap.get(milestone.id);
			if (entry) {
				milestone.status = entry.status;
			}
		}
	}
	// Populate validationVerdict from DB assessments table (#db-first-validation)
	// DB is authoritative; VALIDATION.md is a generated projection only.
	for (const milestone of milestones) {
		const assessment = getMilestoneValidationAssessment(milestone.id);
		if (assessment?.status) {
			const verdict = String(assessment.status).trim().toLowerCase();
			if (
				verdict === "pass" ||
				verdict === "needs-attention" ||
				verdict === "needs-remediation"
			) {
				milestone.validationVerdict = verdict;
			}
		}
	}
	const scopes = [{ scope: "project", label: "project", kind: "project" }];
	for (const milestone of milestones) {
		scopes.push({
			scope: milestone.id,
			label: `${milestone.id}: ${milestone.title}`,
			kind: "milestone",
		});
		for (const slice of milestone.slices) {
			scopes.push({
				scope: `${milestone.id}/${slice.id}`,
				label: `${milestone.id}/${slice.id}: ${slice.title}`,
				kind: "slice",
			});
			for (const task of slice.tasks) {
				scopes.push({
					scope: `${milestone.id}/${slice.id}/${task.id}`,
					label: `${milestone.id}/${slice.id}/${task.id}: ${task.title}`,
					kind: "task",
				});
			}
		}
	}
	return { milestones, active, scopes, validationIssues: [] };
}
export async function listDoctorScopeSuggestions(basePath) {
	const index = await indexWorkspace(basePath);
	const activeSliceScope =
		index.active.milestoneId && index.active.sliceId
			? `${index.active.milestoneId}/${index.active.sliceId}`
			: null;
	const ordered = [...index.scopes].filter((scope) => scope.kind !== "project");
	ordered.sort((a, b) => {
		if (activeSliceScope && a.scope === activeSliceScope) return -1;
		if (activeSliceScope && b.scope === activeSliceScope) return 1;
		return a.scope.localeCompare(b.scope);
	});
	return ordered.map((scope) => ({ value: scope.scope, label: scope.label }));
}
export async function getSuggestedNextCommands(basePath) {
	const index = await indexWorkspace(basePath);
	const scope =
		index.active.milestoneId && index.active.sliceId
			? `${index.active.milestoneId}/${index.active.sliceId}`
			: index.active.milestoneId;
	const commands = new Set();
	if (index.active.phase === "planning") commands.add("/next");
	if (
		index.active.phase === "executing" ||
		index.active.phase === "summarizing"
	)
		commands.add("/autonomous");
	if (scope) commands.add(`/doctor ${scope}`);
	if (scope) commands.add(`/doctor fix ${scope}`);
	commands.add("/status");
	return [...commands];
}
