/**
 * uok-metrics-exposition.test.mjs — Prometheus metrics cache behaviour.
 *
 * Purpose: prove cached UOK metric snapshots are explicitly refreshable so
 * health surfaces can trade scrape cost for freshness without serving stale
 * data after known DB writes.
 */
import assert from "node:assert/strict";
import { mkdtempSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, test } from "vitest";
import {
	closeDatabase,
	insertGateRun,
	insertUokMessage,
	openDatabase,
} from "../sf-db.js";
import {
	invalidateMetricsCache,
	readUokMetrics,
	writeUokMetrics,
} from "../uok/metrics-exposition.js";

const tmpDirs = [];

afterEach(() => {
	closeDatabase();
	invalidateMetricsCache();
	while (tmpDirs.length > 0) {
		const dir = tmpDirs.pop();
		if (dir) rmSync(dir, { recursive: true, force: true });
	}
});

function makeProject() {
	const dir = mkdtempSync(join(tmpdir(), "sf-uok-metrics-"));
	tmpDirs.push(dir);
	openDatabase(":memory:");
	return dir;
}

function recordGateRun(outcome, evaluatedAt = new Date().toISOString()) {
	insertGateRun({
		traceId: `trace-${outcome}`,
		turnId: `turn-${outcome}`,
		gateId: "cache-gate",
		gateType: "verification",
		unitType: "execute-task",
		unitId: "M001/S01/T01",
		milestoneId: "M001",
		sliceId: "S01",
		taskId: "T01",
		outcome,
		failureClass: outcome === "pass" ? "" : "assertion",
		rationale: outcome,
		findings: "",
		attempt: 1,
		maxAttempts: 1,
		retryable: false,
		evaluatedAt,
		durationMs: outcome === "pass" ? 10 : 20,
	});
}

test("writeUokMetrics_when_cache_invalidated_refreshes_db_snapshot", () => {
	const project = makeProject();
	recordGateRun("pass");

	writeUokMetrics(project, ["cache-gate"]);
	const first = readUokMetrics(project);
	assert.match(first, /uok_gate_runs_total\{gate_id="cache-gate"\} 1/);

	recordGateRun("fail");
	writeUokMetrics(project, ["cache-gate"]);
	const cached = readUokMetrics(project);
	assert.match(cached, /uok_gate_runs_total\{gate_id="cache-gate"\} 1/);

	invalidateMetricsCache();
	writeUokMetrics(project, ["cache-gate"]);
	const refreshed = readUokMetrics(project);
	assert.match(refreshed, /uok_gate_runs_total\{gate_id="cache-gate"\} 2/);
	assert.match(
		refreshed,
		/uok_gate_runs_failed_total\{gate_id="cache-gate"\} 1/,
	);
});

test("writeUokMetrics_includes_message_bus_metrics", () => {
	const project = makeProject();
	insertUokMessage({
		id: "msg-1",
		from: "agent-a",
		to: "agent-b",
		body: "hello",
		sentAt: new Date().toISOString(),
		metadata: {},
	});
	writeUokMetrics(project);
	const text = readUokMetrics(project);
	assert.match(text, /uok_message_bus_total_messages 1/);
	assert.match(text, /uok_message_bus_unread_messages 1/);
	assert.match(text, /uok_message_bus_unique_agents 1/);
	assert.match(text, /uok_message_bus_unique_conversations 1/);
});
