const PLACEHOLDER_VALUES = new Set([
	"",
	"not provided.",
	"missing vision alignment meeting.",
	"missing weighted synthesis.",
	"missing confidence by area.",
]);

/**
 * Minimum character count for a milestone ceremony field to be considered
 * "purposeful". Vision meeting fields below this length typically lack the
 * specific evidence, risks, or subsystem references each role requires.
 *
 * Purpose: prevent rubber-stamp ceremony fields from passing validation.
 * Consumer: inspectMilestoneRoadmapMarkdown.
 */
const MIN_PURPOSEFUL_LENGTH = 80;

function isMeaningful(value) {
	const normalized = (value ?? "").trim().toLowerCase();
	return normalized.length > 0 && !PLACEHOLDER_VALUES.has(normalized);
}

/**
 * Check whether a milestone ceremony field is purposeful — present AND substantive
 * enough to serve its role's purpose.
 *
 * Purpose: enforce depth contracts for vision meeting roles.
 * Consumer: inspectMilestoneRoadmapMarkdown (advisory warnings).
 */
function isPurposefulVisionField(value) {
	const trimmed = (value ?? "").trim();
	return trimmed.length >= MIN_PURPOSEFUL_LENGTH;
}
function normalizeVisionMeetingRoute(value) {
	const firstLine = (value ?? "")
		.split(/\r?\n/)
		.map((line) => line.trim())
		.find((line) => line.length > 0);
	if (!firstLine) return undefined;
	const cleaned = firstLine.toLowerCase().replace(/[`*_~]/g, " ");
	const match = cleaned.match(/\b(planning|researching|discussing)\b/);
	return match?.[1];
}
function extractSection(content, heading) {
	const lines = content.split("\n");
	const start = lines.findIndex((line) => line.trim() === `## ${heading}`);
	if (start === -1) return "";
	let end = lines.length;
	for (let index = start + 1; index < lines.length; index += 1) {
		if (/^##\s+/.test(lines[index])) {
			end = index;
			break;
		}
	}
	return lines
		.slice(start + 1, end)
		.join("\n")
		.trim();
}
function extractSubsection(content, heading) {
	const lines = content.split("\n");
	const start = lines.findIndex((line) => line.trim() === `### ${heading}`);
	if (start === -1) return "";
	let end = lines.length;
	for (let index = start + 1; index < lines.length; index += 1) {
		if (/^###\s+/.test(lines[index]) || /^##\s+/.test(lines[index])) {
			end = index;
			break;
		}
	}
	return lines
		.slice(start + 1, end)
		.join("\n")
		.trim();
}
export function hasStructuredVisionAlignmentMeeting(meeting) {
	if (!meeting) return false;
	const route = meeting.recommendedRoute;
	return (
		isMeaningful(meeting.trigger) &&
		isMeaningful(meeting.pm) &&
		isMeaningful(meeting.userAdvocate) &&
		isMeaningful(meeting.customerPanel) &&
		isMeaningful(meeting.business) &&
		isMeaningful(meeting.researcher) &&
		isMeaningful(meeting.deliveryLead) &&
		isMeaningful(meeting.partner) &&
		isMeaningful(meeting.combatant) &&
		isMeaningful(meeting.architect) &&
		isMeaningful(meeting.moderator) &&
		isMeaningful(meeting.weightedSynthesis) &&
		isMeaningful(meeting.confidenceByArea) &&
		(route === "discussing" || route === "researching" || route === "planning")
	);
}
export function getVisionAlignmentBlockingIssue(meeting) {
	if (!meeting) return "missing vision alignment meeting";
	if (!isMeaningful(meeting.trigger)) return "missing vision meeting trigger";
	if (!isMeaningful(meeting.pm)) return "missing vision meeting pm view";
	if (!isMeaningful(meeting.userAdvocate))
		return "missing vision meeting user advocate view";
	if (!isMeaningful(meeting.customerPanel))
		return "missing vision meeting customer panel view";
	if (!isMeaningful(meeting.business))
		return "missing vision meeting business view";
	if (!isMeaningful(meeting.researcher))
		return "missing vision meeting researcher view";
	if (!isMeaningful(meeting.deliveryLead))
		return "missing vision meeting delivery lead view";
	if (!isMeaningful(meeting.partner))
		return "missing vision meeting partner view";
	if (!isMeaningful(meeting.combatant))
		return "missing vision meeting combatant view";
	if (!isMeaningful(meeting.architect))
		return "missing vision meeting architect view";
	if (!isMeaningful(meeting.moderator))
		return "missing vision meeting moderator decision";
	if (!isMeaningful(meeting.weightedSynthesis))
		return "missing weighted synthesis";
	if (!isMeaningful(meeting.confidenceByArea))
		return "missing confidence by area";
	if (meeting.recommendedRoute && meeting.recommendedRoute !== "planning") {
		return `vision meeting routed back to ${meeting.recommendedRoute}`;
	}
	if (
		meeting.recommendedRoute !== "planning" &&
		meeting.recommendedRoute !== "researching" &&
		meeting.recommendedRoute !== "discussing"
	) {
		return "invalid vision meeting route";
	}
	return null;
}
export function inspectMilestoneRoadmapMarkdown(content) {
	const issues = [];
	const meetingSection = extractSection(content, "Vision Alignment Meeting");
	if (!meetingSection) {
		issues.push("missing vision alignment meeting");
		return { issues };
	}
	const meeting = {
		trigger: extractSubsection(meetingSection, "Trigger"),
		pm: extractSubsection(meetingSection, "Product Manager"),
		userAdvocate: extractSubsection(meetingSection, "User Advocate"),
		customerPanel: extractSubsection(meetingSection, "Customer Panel"),
		business: extractSubsection(meetingSection, "Business"),
		researcher: extractSubsection(meetingSection, "Researcher"),
		deliveryLead: extractSubsection(meetingSection, "Delivery Lead"),
		partner: extractSubsection(meetingSection, "Partner"),
		combatant: extractSubsection(meetingSection, "Combatant"),
		architect: extractSubsection(meetingSection, "Architect"),
		moderator: extractSubsection(meetingSection, "Moderator"),
		weightedSynthesis: extractSubsection(meetingSection, "Weighted Synthesis"),
		confidenceByArea: extractSubsection(meetingSection, "Confidence By Area"),
		recommendedRoute: normalizeVisionMeetingRoute(
			extractSubsection(meetingSection, "Recommended Route"),
		),
	};
	const blockingIssue = getVisionAlignmentBlockingIssue(meeting);
	if (blockingIssue) issues.push(blockingIssue);
	// Advisory depth checks — warn on shallow ceremony fields that pass presence
	if (
		isMeaningful(meeting.partner) &&
		!isPurposefulVisionField(meeting.partner)
	)
		issues.push(
			"shallow partner review — cite specific evidence (source files, prior milestones, production incidents)",
		);
	if (
		isMeaningful(meeting.combatant) &&
		!isPurposefulVisionField(meeting.combatant)
	)
		issues.push(
			"shallow combatant review — name specific risks with concrete failure scenarios",
		);
	if (
		isMeaningful(meeting.architect) &&
		!isPurposefulVisionField(meeting.architect)
	)
		issues.push(
			"shallow architect review — name affected subsystems, coupling points, and dependency rationale",
		);
	if (
		isMeaningful(meeting.researcher) &&
		!isPurposefulVisionField(meeting.researcher)
	)
		issues.push(
			"shallow researcher review — cite at least one external source or comparable system",
		);
	if (
		isMeaningful(meeting.weightedSynthesis) &&
		!isPurposefulVisionField(meeting.weightedSynthesis)
	)
		issues.push(
			"shallow weighted synthesis — must identify the strongest additions, cuts, and sequencing changes",
		);
	// BUILD_PLAN reference check (advisory — not a hard block for legacy milestones)
	if (!content.includes("BUILD_PLAN")) {
		issues.push(
			"missing BUILD_PLAN.md reference — new milestones should cite which BUILD_PLAN tier/item they implement (D015)",
		);
	}
	return { issues };
}
export function getMilestonePlanBlockingIssue(content) {
	const check = inspectMilestoneRoadmapMarkdown(content);
	return check.issues[0] ?? null;
}
