/**
 * Remediation Dispatcher — autonomous recovery from validation findings.
 *
 * Purpose: when verification fails after execute-task, decide whether to
 * retry, replan, research, or escalate - then execute the decision
 * without operator intervention.
 *
 * Consumer: auto-verification.js after verification gate fails.
 *
 * The dispatcher classifies failure patterns using the verification result
 * and maps each pattern to a remediation strategy:
 *
 *   transient    -> retry immediately (network, flaky test)
 *   structural   -> replan slice (broken import, missing file)
 *   knowledge    -> research slice (unknown API, unclear spec)
 *   infra        -> escalate via self-feedback (tooling broken)
 *
 * Confidence scoring determines whether to act autonomously or pause
 * for human review. High-confidence structural fixes proceed; low-
 * confidence escalations always pause.
 */
import { recordSelfFeedback } from "./self-feedback.js";

// ─── Failure classification heuristics ─────────────────────────────────────

const TRANSIENT_PATTERNS = [
	/timeout|ETIMEDOUT|ECONNRESET|ECONNREFUSED/i,
	/flaky|intermittent|race condition/i,
	/lock|EBUSY|EACCES.*temp/i,
];

const STRUCTURAL_PATTERNS = [
	/cannot find module|cannot resolve|import.*not found/i,
	/syntax error|unexpected token|parse error/i,
	/type.*error|reference.*error/i,
];

const KNOWLEDGE_PATTERNS = [
	/unknown|not implemented|todo|fixme|stub/i,
	/missing.*context|insufficient.*information|ambiguous/i,
];

const INFRA_PATTERNS = [
	/command not found|ENOENT.*jest|ENOENT.*vitest|ENOENT.*eslint/i,
	/module.*not found.*in.*path|global.*install/i,
	/config.*error|invalid.*config|missing.*config/i,
];

/**
 * Classify a failed verification check into a remediation class.
 *
 * Purpose: turn raw command stderr into a bounded remediation strategy so
 * autonomous verification can retry or escalate for a concrete reason.
 *
 * Consumer: decideRemediation and remediation dispatcher tests.
 */
export function classifyFailure(stderr = "", exitCode = 1) {
	const text = stderr.toLowerCase();
	for (const p of INFRA_PATTERNS) if (p.test(text)) return "infra";
	for (const p of STRUCTURAL_PATTERNS) if (p.test(text)) return "structural";
	for (const p of KNOWLEDGE_PATTERNS) if (p.test(text)) return "knowledge";
	for (const p of TRANSIENT_PATTERNS) if (p.test(text)) return "transient";
	// Default heuristic: exit code 1 with short stderr = transient; long stderr = structural
	if (exitCode === 1 && stderr.length < 200) return "transient";
	return "structural";
}

// ─── Confidence scoring ────────────────────────────────────────────────────

/**
 * Score confidence in a remediation class.
 *
 * Purpose: prevent autonomous remediation from repeatedly acting on weak or
 * noisy failure signals after prior attempts already failed.
 *
 * Consumer: decideRemediation before choosing retry/replan/research/escalate.
 */
export function computeConfidence(failureClass, result) {
	const checks = result.checks ?? [];
	const failedChecks = checks.filter((c) => c.exitCode !== 0);
	if (failedChecks.length === 0) return 0;

	// Single failing check with known pattern = higher confidence
	const patternStrength = failedChecks.length === 1 ? 0.8 : 0.45;

	// Previous retry history reduces confidence
	const attempt = result.attempt ?? 0;
	const attemptPenalty = attempt * 0.2;

	// Transient failures are higher confidence to auto-fix
	const classBoost =
		failureClass === "transient"
			? 0.2
			: failureClass === "structural"
				? 0.1
				: 0;

	return Math.max(
		0,
		Math.min(1, patternStrength + classBoost - attemptPenalty),
	);
}

// ─── Remediation strategies ────────────────────────────────────────────────

/**
 * Decide and execute remediation for a verification failure.
 *
 * Returns a remediation decision for the caller to execute.
 *
 * Purpose: provide one deterministic policy boundary between verification
 * failures and autonomous recovery actions.
 *
 * Consumer: auto-verification after a verification gate fails.
 */
export function decideRemediation(result, opts = {}) {
	const failedChecks = (result.checks ?? []).filter((c) => c.exitCode !== 0);
	if (failedChecks.length === 0) {
		return { action: "continue", reason: "no failed checks", confidence: 1 };
	}

	// Use the first (or most severe) failing check for classification
	const primary = failedChecks[0];
	const failureClass = classifyFailure(primary.stderr, primary.exitCode);
	const confidence = computeConfidence(failureClass, result);

	// Low confidence always escalates
	if (confidence < 0.4) {
		return {
			action: "escalate",
			reason: `Low confidence (${confidence.toFixed(2)}) in ${failureClass} classification`,
			confidence,
			failureClass,
		};
	}

	// High confidence but structural/knowledge may need human review
	const autoFixThreshold = opts.autoFixThreshold ?? 0.6;
	if (confidence < autoFixThreshold && failureClass !== "transient") {
		return {
			action: "pause",
			reason: `Confidence ${confidence.toFixed(2)} below auto-fix threshold for ${failureClass}`,
			confidence,
			failureClass,
		};
	}

	switch (failureClass) {
		case "transient":
			return {
				action: "retry",
				reason: `Transient failure detected: ${primary.command} (${primary.exitCode})`,
				confidence,
				failureClass,
			};
		case "structural":
			return {
				action: "replan",
				reason: `Structural failure: ${primary.command} - replanning slice`,
				confidence,
				failureClass,
			};
		case "knowledge":
			return {
				action: "research",
				reason: `Knowledge gap: ${primary.command} - researching before retry`,
				confidence,
				failureClass,
			};
		case "infra":
			return {
				action: "escalate",
				reason: `Infrastructure failure: ${primary.command} - tooling issue`,
				confidence,
				failureClass,
			};
		default:
			return {
				action: "pause",
				reason: `Unclassified failure - pausing for review`,
				confidence: 0,
				failureClass: "unknown",
			};
	}
}

/**
 * Execute the remediation decision and record observability.
 *
 * Returns true if the remediation was handled without needing to pause.
 */
export async function executeRemediation(decision, basePath, ctx) {
	switch (decision.action) {
		case "continue":
			return true;
		case "retry":
			// Retry is handled by the caller (auto-verification sets pendingVerificationRetry)
			return true;
		case "replan":
			// File self-feedback requesting replan
			recordSelfFeedback(
				{
					kind: "gap:verification-structural-failure",
					severity: "medium",
					summary:
						"Verification found structural failure - replanning recommended",
					evidence: decision.reason,
					suggestedFix: "Run replan-slice for the active slice",
				},
				basePath,
			);
			return false; // pause so operator can review replan
		case "research":
			recordSelfFeedback(
				{
					kind: "gap:verification-knowledge-gap",
					severity: "medium",
					summary: "Verification found knowledge gap - research needed",
					evidence: decision.reason,
					suggestedFix: "Run research-slice for the active slice",
				},
				basePath,
			);
			return false;
		case "escalate":
			recordSelfFeedback(
				{
					kind: "gap:verification-infra-failure",
					severity: "high",
					summary: "Verification found infrastructure failure",
					evidence: decision.reason,
					suggestedFix: "Check tooling and configuration",
				},
				basePath,
			);
			ctx?.ui?.notify(
				`Infrastructure failure escalated to self-feedback: ${decision.reason}`,
				"error",
			);
			return false;
		default:
			return false;
	}
}
