// SF Extension — State Shared Helpers
// Helpers shared by both the DB-backed (state-db.js) and legacy filesystem
// (state-legacy.js) state derivation paths. No dependency on either.

import { existsSync } from "node:fs";
import { join } from "node:path";
import { isTerminalMilestoneSummaryContent } from "./milestone-summary-classifier.js";
import { resolveMilestoneFile, sfRoot } from "./paths.js";
import {
	getMilestone,
	getMilestoneValidationAssessment,
	isDbAvailable,
} from "./sf-db.js";
import { extractVerdict } from "./verdict-parser.js";

export function isGhostMilestone(basePath, mid) {
	// If the milestone has a DB row, it's usually a known milestone — not a ghost.
	// Exception: a "queued" row with no disk artifacts is a phantom from
	// new_milestone_id that was never planned (#3645).
	if (isDbAvailable()) {
		const dbRow = getMilestone(mid);
		if (dbRow) {
			if (dbRow.status === "queued") {
				const hasContent =
					resolveMilestoneFile(basePath, mid, "CONTEXT") ||
					resolveMilestoneFile(basePath, mid, "CONTEXT-DRAFT") ||
					resolveMilestoneFile(basePath, mid, "ROADMAP") ||
					resolveMilestoneFile(basePath, mid, "SUMMARY");
				return !hasContent;
			}
			return false;
		}
	}
	// If a worktree exists for this milestone, it was legitimately created.
	const root = sfRoot(basePath);
	const wtPath = join(root, "worktrees", mid);
	if (existsSync(wtPath)) return false;
	// Fall back to content-file check: no substantive files means ghost.
	const context = resolveMilestoneFile(basePath, mid, "CONTEXT");
	const draft = resolveMilestoneFile(basePath, mid, "CONTEXT-DRAFT");
	const roadmap = resolveMilestoneFile(basePath, mid, "ROADMAP");
	const summary = resolveMilestoneFile(basePath, mid, "SUMMARY");
	return !context && !draft && !roadmap && !summary;
}
// ─── Query Functions ───────────────────────────────────────────────────────
/**
 * Check if all tasks in a slice plan are done.
 */
export function isSliceComplete(plan) {
	return plan.tasks.length > 0 && plan.tasks.every((t) => t.done);
}
/**
 * Check if all slices in a roadmap are done.
 */
export function isMilestoneComplete(roadmap) {
	return roadmap.slices.length > 0 && roadmap.slices.every((s) => s.done);
}
/**
 * Check whether a VALIDATION file's verdict is terminal.
 * Any successfully extracted verdict (pass, needs-attention, needs-remediation,
 * fail, etc.) means validation completed. Only return false when no verdict
 * could be parsed — i.e. extractVerdict() returns undefined (#2769).
 */
export function isValidationTerminal(validationContent) {
	return extractVerdict(validationContent) != null;
}
function getDbMilestoneValidationVerdict(milestoneId) {
	if (!isDbAvailable()) return undefined;
	const assessment = getMilestoneValidationAssessment(milestoneId);
	const status = assessment?.status;
	return typeof status === "string" && status.trim()
		? status.trim().toLowerCase()
		: undefined;
}
export async function readMilestoneValidationVerdict(
	basePath,
	milestoneId,
	load,
) {
	const dbVerdict = getDbMilestoneValidationVerdict(milestoneId);
	if (dbVerdict) {
		return { terminal: true, verdict: dbVerdict };
	}
	if (isDbAvailable()) {
		return { terminal: false, verdict: undefined, source: "db-missing" };
	}
	const validationFile = resolveMilestoneFile(
		basePath,
		milestoneId,
		"VALIDATION",
	);
	const validationContent = validationFile ? await load(validationFile) : null;
	return {
		terminal: validationContent
			? isValidationTerminal(validationContent)
			: false,
		verdict: validationContent ? extractVerdict(validationContent) : undefined,
	};
}
export async function loadTerminalSummary(summaryFile, loadFn) {
	if (!summaryFile) return null;
	const sc = await loadFn(summaryFile);
	if (sc == null || !isTerminalMilestoneSummaryContent(sc)) return null;
	return sc;
}
export function stripMilestonePrefix(title) {
	return title.replace(/^M\d+(?:-[a-z0-9]{6})?[^:]*:\s*/, "") || title;
}
export function canonicalMilestonePrefix(id) {
	return id.match(/^([A-Z]\d{3})/)?.[1] ?? id;
}
export function extractContextTitle(content, fallback) {
	if (!content) return fallback;
	const h1 = content.split("\n").find((line) => line.startsWith("# "));
	if (!h1) return fallback;
	// Extract title from "# M005: Platform Foundation & Separation" format
	return stripMilestonePrefix(h1.slice(2).trim()) || fallback;
}
