/**
 * detector-repeated-feedback-kind.test.mjs — repeated feedback detector contracts.
 *
 * Purpose: prove R053 fires only when the same feedback kind targets the same
 * planning object often enough inside the detector window.
 */
import assert from "node:assert/strict";
import { test } from "vitest";
import {
	MIN_OCCURRENCES,
	WINDOW_MS,
	detectRepeatedFeedbackKind,
} from "../detectors/repeated-feedback-kind.js";

const NOW = Date.parse("2026-05-17T12:00:00.000Z");

function feedback(overrides = {}) {
	return {
		kind: "zero-progress",
		occurredIn: { task: "T01" },
		timestamp: NOW - 5 * 60 * 1000,
		...overrides,
	};
}

test("detectRepeatedFeedbackKind_when_same_kind_and_target_reaches_threshold_returns_stuck", () => {
	const result = detectRepeatedFeedbackKind(
		[
			feedback(),
			feedback({ timestamp: NOW - 10 * 60 * 1000 }),
			feedback({ timestamp: NOW - 20 * 60 * 1000 }),
		],
		{ now: NOW },
	);

	assert.equal(result.stuck, true);
	assert.equal(result.reason, "repeated-feedback-kind");
	assert.deepEqual(result.signature, {
		kind: "zero-progress",
		target: "task:T01",
		occurrences: MIN_OCCURRENCES,
		windowMs: WINDOW_MS,
	});
});

test("detectRepeatedFeedbackKind_when_kind_or_target_differs_returns_not_stuck", () => {
	const result = detectRepeatedFeedbackKind(
		[
			feedback(),
			feedback({ kind: "stale-lock" }),
			feedback({ occurredIn: { task: "T02" } }),
		],
		{ now: NOW },
	);

	assert.deepEqual(result, { stuck: false });
});

test("detectRepeatedFeedbackKind_when_exactly_one_below_threshold_returns_not_stuck", () => {
	const result = detectRepeatedFeedbackKind(
		Array.from({ length: MIN_OCCURRENCES - 1 }, (_, index) =>
			feedback({ timestamp: NOW - index * 60 * 1000 }),
		),
		{ now: NOW },
	);

	assert.deepEqual(result, { stuck: false });
});

test("detectRepeatedFeedbackKind_when_oldest_entry_is_outside_window_returns_not_stuck", () => {
	const result = detectRepeatedFeedbackKind(
		[
			feedback({ timestamp: NOW - WINDOW_MS - 1 }),
			feedback({ timestamp: NOW - 10 * 60 * 1000 }),
			feedback({ timestamp: NOW - 20 * 60 * 1000 }),
		],
		{ now: NOW },
	);

	assert.deepEqual(result, { stuck: false });
});
