import { describe, expect, test } from "vitest";
import {
	createLoopSignal,
	detectorSweepSignal,
	duplicateSearchSignal,
	repeatedToolCallSignal,
	repeatedToolFailureSignal,
	zeroProgressSignal,
} from "../supervision/loop-signals.js";

describe("loop supervision signals", () => {
	test("createLoopSignal_when_invalid_fields_supplied_normalizes_to_safe_contract", () => {
		const signal = createLoopSignal({
			scope: "bad",
			kind: "duplicate-tool-call",
			severity: "bad",
			recommendedAction: "bad",
			evidence: "same args",
		});

		expect(signal).toMatchObject({
			scope: "unit",
			kind: "duplicate-tool-call",
			severity: "warning",
			recommendedAction: "pause",
			evidence: { value: "same args" },
		});
	});

	test("detectorSweepSignal_when_detector_fires_preserves_unit_and_signature", () => {
		const signal = detectorSweepSignal(
			{ name: "artifact-flap", signature: { path: "SUMMARY.md" } },
			"execute-task",
			"M001/S01/T01",
			123,
		);

		expect(signal).toMatchObject({
			scope: "unit",
			kind: "wiggums:artifact-flap",
			severity: "fail",
			unit: { type: "execute-task", id: "M001/S01/T01" },
			recommendedAction: "pause",
			evidence: {
				detector: "artifact-flap",
				signature: { path: "SUMMARY.md" },
				failedAt: 123,
			},
		});
	});

	test("zeroProgressSignal_when_detector_fires_uses_same_supervision_contract", () => {
		const signal = zeroProgressSignal({
			unitType: "execute-task",
			unitId: "M002/S03/T04",
			evidence: { toolCallsTotal: 25 },
		});

		expect(signal).toMatchObject({
			scope: "unit",
			kind: "zero-progress",
			severity: "fail",
			unit: { type: "execute-task", id: "M002/S03/T04" },
			recommendedAction: "pause",
			evidence: { toolCallsTotal: 25 },
		});
	});

	test("repeatedToolCallSignal_when_guard_blocks_preserves_tool_evidence", () => {
		const signal = repeatedToolCallSignal({
			toolName: "ask_user_questions",
			count: 2,
			threshold: 1,
			signature: "abc123",
		});

		expect(signal).toMatchObject({
			scope: "tool",
			kind: "tool-call:duplicate",
			severity: "fail",
			recommendedAction: "block",
			source: "tool-call-loop-guard",
			evidence: {
				toolName: "ask_user_questions",
				count: 2,
				threshold: 1,
				signature: "abc123",
			},
		});
	});

	test("repeatedToolFailureSignal_when_watchdog_steers_preserves_command_evidence", () => {
		const signal = repeatedToolFailureSignal({
			toolName: "Bash",
			command: "npm test",
			count: 2,
			windowMs: 600000,
			excerpt: "failed",
		});

		expect(signal).toMatchObject({
			scope: "tool",
			kind: "tool-result:repeated-failure",
			severity: "warning",
			recommendedAction: "continue",
			source: "tool-watchdog",
			evidence: {
				toolName: "Bash",
				command: "npm test",
				count: 2,
				windowMs: 600000,
				excerpt: "failed",
			},
		});
	});

	test("duplicateSearchSignal_when_search_guard_blocks_preserves_query_evidence", () => {
		const signal = duplicateSearchSignal({
			query: "sf autonomous loops",
			provider: "tavily",
			domain: "example.com",
			consecutiveDupeCount: 2,
		});

		expect(signal).toMatchObject({
			scope: "tool",
			kind: "search:duplicate-query",
			severity: "fail",
			recommendedAction: "block",
			source: "search-the-web",
			evidence: {
				query: "sf autonomous loops",
				provider: "tavily",
				domain: "example.com",
				consecutiveDupeCount: 2,
			},
		});
	});
});
