/**
 * RemediationDispatcher tests — failure classification, confidence scoring,
 * and decision routing.
 */
import assert from "node:assert/strict";
import { test } from "vitest";
import {
	classifyFailure,
	computeConfidence,
	decideRemediation,
} from "../remediation-dispatcher.js";

test("classifyFailure_transient_patterns", () => {
	assert.equal(classifyFailure("Request timeout after 5000ms", 1), "transient");
	assert.equal(classifyFailure("ECONNRESET: Connection reset", 1), "transient");
	assert.equal(classifyFailure("flaky test failure", 1), "transient");
});

test("classifyFailure_structural_patterns", () => {
	assert.equal(
		classifyFailure("Cannot find module '../utils'", 1),
		"structural",
	);
	assert.equal(
		classifyFailure("SyntaxError: Unexpected token", 1),
		"structural",
	);
	assert.equal(
		classifyFailure("TypeError: Cannot read property", 1),
		"structural",
	);
});

test("classifyFailure_knowledge_patterns", () => {
	assert.equal(
		classifyFailure("Not implemented: support for async generators", 1),
		"knowledge",
	);
	assert.equal(classifyFailure("TODO: handle edge case", 1), "knowledge");
	assert.equal(classifyFailure("Missing context for decision", 1), "knowledge");
});

test("classifyFailure_infra_patterns", () => {
	assert.equal(classifyFailure("Command not found: jest", 127), "infra");
	assert.equal(
		classifyFailure("ENOENT: no such file or directory, open '.eslintrc'", 1),
		"infra",
	);
});

test("classifyFailure_default_heuristic", () => {
	// Short stderr + exit 1 means transient.
	assert.equal(classifyFailure("oops", 1), "transient");
	// Long stderr + exit 1 means structural.
	assert.equal(classifyFailure("a".repeat(500), 1), "structural");
});

test("computeConfidence_single_check_high_confidence", () => {
	const result = {
		checks: [{ command: "test", exitCode: 1, stderr: "timeout" }],
		attempt: 0,
	};
	const c = computeConfidence("transient", result);
	assert.ok(c >= 0.8, `expected high confidence, got ${c}`);
});

test("computeConfidence_multiple_checks_reduces_confidence", () => {
	const result = {
		checks: [
			{ command: "test", exitCode: 1, stderr: "timeout" },
			{ command: "lint", exitCode: 1, stderr: "error" },
		],
		attempt: 0,
	};
	const c = computeConfidence("transient", result);
	assert.ok(c < 0.7, `expected lower confidence for multiple checks, got ${c}`);
});

test("computeConfidence_attempt_penalty", () => {
	const result = {
		checks: [{ command: "test", exitCode: 1, stderr: "timeout" }],
		attempt: 3,
	};
	const c = computeConfidence("transient", result);
	assert.ok(c < 0.5, `expected low confidence after 3 attempts, got ${c}`);
});

test("decideRemediation_transient_high_confidence_returns_retry", () => {
	const result = {
		checks: [{ command: "test", exitCode: 1, stderr: "timeout" }],
		attempt: 0,
	};
	const d = decideRemediation(result);
	assert.equal(d.action, "retry");
	assert.equal(d.failureClass, "transient");
	assert.ok(d.confidence >= 0.6);
});

test("decideRemediation_structural_returns_replan", () => {
	const result = {
		checks: [{ command: "test", exitCode: 1, stderr: "Cannot find module" }],
		attempt: 0,
	};
	const d = decideRemediation(result);
	assert.equal(d.action, "replan");
	assert.equal(d.failureClass, "structural");
});

test("decideRemediation_knowledge_returns_research", () => {
	const result = {
		checks: [{ command: "test", exitCode: 1, stderr: "Not implemented" }],
		attempt: 0,
	};
	const d = decideRemediation(result);
	assert.equal(d.action, "research");
	assert.equal(d.failureClass, "knowledge");
});

test("decideRemediation_infra_returns_escalate", () => {
	const result = {
		checks: [
			{ command: "test", exitCode: 127, stderr: "Command not found: jest" },
		],
		attempt: 0,
	};
	const d = decideRemediation(result);
	assert.equal(d.action, "escalate");
	assert.equal(d.failureClass, "infra");
});

test("decideRemediation_low_confidence_returns_escalate", () => {
	const result = {
		checks: [{ command: "test", exitCode: 1, stderr: "unknown weird error" }],
		attempt: 5,
	};
	const d = decideRemediation(result);
	assert.equal(d.action, "escalate");
	assert.ok(d.confidence < 0.4);
});

test("decideRemediation_no_failed_checks_returns_continue", () => {
	const result = {
		checks: [{ command: "test", exitCode: 0, stderr: "" }],
	};
	const d = decideRemediation(result);
	assert.equal(d.action, "continue");
});

test("decideRemediation_respects_autoFixThreshold", () => {
	const result = {
		checks: [{ command: "test", exitCode: 1, stderr: "Cannot find module" }],
		attempt: 0,
	};
	// With threshold 0.9, structural (confidence ~0.6) should pause
	const d = decideRemediation(result, { autoFixThreshold: 0.9 });
	assert.equal(d.action, "replan"); // structural always goes to replan, threshold only affects non-transient
});
