/**
 * headless-uok-status.ts — `sf headless status uok`
 *
 * Purpose: expose UOK gate health (recent outcomes, circuit breaker states,
 * failure streaks) via the headless CLI so operators can inspect autonomous
 * reliability without digging through DB or log files.
 *
 * Consumer: headless.ts when command === "status" && commandArgs[0] === "uok"
 */

import { existsSync } from "node:fs";
import { join } from "node:path";
import { createJiti } from "@mariozechner/jiti";
import { resolveBundledSourceResource } from "./bundled-resource-path.js";
import { getSfEnv } from "./env.js";

const jiti = createJiti(import.meta.filename, {
	interopDefault: true,
	debug: false,
});

const agentExtensionsDir = join(getSfEnv().agentDir, "extensions", "sf");
const useAgentDir = existsSync(join(agentExtensionsDir, "state.js"));

function sfExtensionPath(moduleName: string): string {
	if (useAgentDir) return join(agentExtensionsDir, `${moduleName}.js`);
	const tsPath = resolveBundledSourceResource(
		import.meta.url,
		"extensions",
		"sf",
		`${moduleName}.ts`,
	);
	if (existsSync(tsPath)) return tsPath;
	return resolveBundledSourceResource(
		import.meta.url,
		"extensions",
		"sf",
		`${moduleName}.js`,
	);
}

export interface GateHealthEntry {
	id: string;
	scope: string;
	total: number;
	pass: number;
	fail: number;
	retry: number;
	lastEvaluatedAt: string | null;
	circuitBreaker: string;
	failureStreak: number;
}

export interface UokStatusResult {
	exitCode: number;
	gates: GateHealthEntry[];
}

function passRate(entry: GateHealthEntry): string {
	if (entry.total === 0) return "—";
	return `${Math.round((entry.pass / entry.total) * 100)}%`;
}

function cbIcon(state: string): string {
	if (state === "open") return "🔴";
	if (state === "half-open") return "🟡";
	return "🟢";
}

function formatTable(gates: GateHealthEntry[]): string {
	if (gates.length === 0) {
		return "No gate run data found in the last 24h.\n";
	}
	const header =
		"| Gate | Scope | Pass% | Pass | Fail | Retry | CB | Streak | Last Evaluated |\n" +
		"|------|-------|-------|------|------|-------|----|--------|----------------|\n";
	const rows = gates
		.map((g) => {
			const last = g.lastEvaluatedAt
				? new Date(g.lastEvaluatedAt)
						.toISOString()
						.replace("T", " ")
						.slice(0, 19)
				: "never";
			return `| ${g.id} | ${g.scope} | ${passRate(g)} | ${g.pass} | ${g.fail} | ${g.retry} | ${cbIcon(g.circuitBreaker)} ${g.circuitBreaker} | ${g.failureStreak} | ${last} |`;
		})
		.join("\n");
	return `${header}${rows}\n`;
}

export async function handleUokStatus(
	basePath: string,
	opts: { json?: boolean } = {},
): Promise<UokStatusResult> {
	let gates: GateHealthEntry[] = [];

	try {
		const autoStartModule = (await jiti.import(
			sfExtensionPath("auto-start"),
			{},
		)) as any;
		await autoStartModule.openProjectDbIfPresent(basePath);

		// Load sf-db-gates directly to avoid the missing getDistinctGateIds
		// import in gate-runner.js getHealthSummary().
		const gatesDbModule = (await jiti.import(
			sfExtensionPath("sf-db/sf-db-gates"),
			{},
		)) as any;

		const gateIds: string[] = gatesDbModule.getDistinctGateIds();

		// Fetch scope and last-evaluated from quality_gates DB for each gate
		const sfDbModule = (await jiti.import(sfExtensionPath("sf-db"), {})) as any;
		const getGateMeta = (
			id: string,
		): { scope: string; lastEvaluatedAt: string | null } => {
			try {
				const db = sfDbModule._getAdapter?.() ?? null;
				if (!db) return { scope: "unknown", lastEvaluatedAt: null };
				const row = db
					.prepare(
						"SELECT scope, MAX(evaluated_at) AS last_eval FROM quality_gates WHERE gate_id = ? LIMIT 1",
					)
					.get(id);
				return {
					scope: row?.scope ?? "unknown",
					lastEvaluatedAt: row?.last_eval ?? null,
				};
			} catch {
				return { scope: "unknown", lastEvaluatedAt: null };
			}
		};

		gates = gateIds.map((id: string) => {
			const stats = gatesDbModule.getGateRunStats(id, 24);
			const cb = gatesDbModule.getGateCircuitBreaker(id);
			const meta = getGateMeta(id);
			return {
				id,
				scope: meta.scope,
				total: stats.total ?? 0,
				pass: stats.pass ?? 0,
				fail: stats.fail ?? 0,
				retry: stats.retry ?? 0,
				// prefer stats window result; fall back to quality_gates last entry
				lastEvaluatedAt: stats.lastEvaluatedAt ?? meta.lastEvaluatedAt,
				circuitBreaker: cb?.state ?? "closed",
				failureStreak: cb?.failureStreak ?? 0,
			} satisfies GateHealthEntry;
		});
	} catch (err) {
		const msg = err instanceof Error ? err.message : String(err);
		process.stderr.write(`[headless] uok-status: ${msg}\n`);
		return { exitCode: 1, gates: [] };
	}

	if (opts.json) {
		process.stdout.write(
			JSON.stringify({ schemaVersion: 1, gates }, null, 2) + "\n",
		);
	} else {
		process.stdout.write("\nUOK Gate Health (last 24h)\n\n");
		process.stdout.write(formatTable(gates));
	}

	return { exitCode: 0, gates };
}
