const PLACEHOLDER_VALUES = new Set([
	"",
	"not provided.",
	"missing adversarial review.",
	"missing partner review.",
	"missing combatant review.",
	"missing architect review.",
]);

/**
 * Minimum character count for a ceremony field to be considered "purposeful"
 * (not just present). Below this threshold, the contribution is too short to
 * contain specific evidence, risks, or subsystem references.
 *
 * Purpose: prevent rubber-stamp ceremony fields from passing validation.
 * Consumer: inspectSlicePlanMarkdown, hasStructuredPlanningMeeting.
 */
const MIN_PURPOSEFUL_LENGTH = 80;

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

/**
 * Check whether a ceremony field is purposeful — present AND substantive enough
 * to serve its role's purpose. A partner that doesn't cite evidence, a combatant
 * that doesn't name specific risks, or an architect that doesn't name subsystems
 * will typically be under this length.
 *
 * Purpose: enforce depth contracts, not just presence.
 * Consumer: inspectSlicePlanMarkdown (advisory warnings, not hard blocks).
 */
function isPurposefulReviewBody(value) {
	const trimmed = (value ?? "").trim();
	return trimmed.length >= MIN_PURPOSEFUL_LENGTH;
}
function normalizePlanningMeetingRoute(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 hasCompleteAdversarialReview(review) {
	return (
		isMeaningfulReviewBody(review?.partner) &&
		isMeaningfulReviewBody(review?.combatant) &&
		isMeaningfulReviewBody(review?.architect)
	);
}
export function hasStructuredPlanningMeeting(meeting) {
	if (!meeting) return false;
	const route = meeting.recommendedRoute;
	return (
		isMeaningfulReviewBody(meeting.trigger) &&
		isMeaningfulReviewBody(meeting.pm) &&
		isMeaningfulReviewBody(meeting.researcher) &&
		isMeaningfulReviewBody(meeting.partner) &&
		isMeaningfulReviewBody(meeting.combatant) &&
		isMeaningfulReviewBody(meeting.architect) &&
		isMeaningfulReviewBody(meeting.moderator) &&
		isMeaningfulReviewBody(meeting.confidenceSummary) &&
		(route === "discussing" || route === "researching" || route === "planning")
	);
}
export function inspectSlicePlanMarkdown(content) {
	const issues = [];
	const adversarialSection = extractSection(content, "Adversarial Review");
	if (!adversarialSection) {
		issues.push("missing adversarial review");
		return { issues };
	}
	const partner = extractSubsection(adversarialSection, "Partner Review");
	const combatant = extractSubsection(adversarialSection, "Combatant Review");
	const architect = extractSubsection(adversarialSection, "Architect Review");
	if (!isMeaningfulReviewBody(partner)) issues.push("missing partner review");
	else if (!isPurposefulReviewBody(partner))
		issues.push(
			"shallow partner review — cite specific evidence (file paths, test gaps, prior learnings)",
		);
	if (!isMeaningfulReviewBody(combatant))
		issues.push("missing combatant review");
	else if (!isPurposefulReviewBody(combatant))
		issues.push(
			"shallow combatant review — name specific risks with concrete failure scenarios",
		);
	if (!isMeaningfulReviewBody(architect))
		issues.push("missing architect review");
	else if (!isPurposefulReviewBody(architect))
		issues.push(
			"shallow architect review — name affected subsystems and coupling points",
		);
	const planningMeeting = extractSection(content, "Planning Meeting");
	if (planningMeeting) {
		const trigger = extractSubsection(planningMeeting, "Trigger");
		const pm = extractSubsection(planningMeeting, "Product Manager");
		const researcher = extractSubsection(planningMeeting, "Researcher");
		const meetingPartner = extractSubsection(planningMeeting, "Partner");
		const meetingCombatant = extractSubsection(planningMeeting, "Combatant");
		const meetingArchitect = extractSubsection(planningMeeting, "Architect");
		const moderator = extractSubsection(planningMeeting, "Moderator");
		const route = normalizePlanningMeetingRoute(
			extractSubsection(planningMeeting, "Recommended Route"),
		);
		const confidence = extractSubsection(planningMeeting, "Confidence");
		if (!isMeaningfulReviewBody(trigger))
			issues.push("missing planning meeting trigger");
		if (!isMeaningfulReviewBody(pm))
			issues.push("missing planning meeting pm review");
		if (!isMeaningfulReviewBody(researcher))
			issues.push("missing planning meeting researcher review");
		if (!isMeaningfulReviewBody(meetingPartner))
			issues.push("missing planning meeting partner review");
		if (!isMeaningfulReviewBody(meetingCombatant))
			issues.push("missing planning meeting combatant review");
		if (!isMeaningfulReviewBody(meetingArchitect))
			issues.push("missing planning meeting architect review");
		if (!isMeaningfulReviewBody(moderator))
			issues.push("missing planning meeting moderator decision");
		if (!isMeaningfulReviewBody(confidence))
			issues.push("missing planning meeting confidence");
		if (
			route &&
			route !== "planning" &&
			route !== "researching" &&
			route !== "discussing"
		) {
			issues.push("invalid planning meeting route");
		} else if (route && route !== "planning") {
			issues.push(`planning meeting routed back to ${route}`);
		}
	}
	return { issues };
}
export function getSlicePlanBlockingIssue(content) {
	const check = inspectSlicePlanMarkdown(content);
	return check.issues[0] ?? null;
}
