/**
 * UOK Autonomous Cost-Guard Gate
 *
 * Purpose: prevent runaway spend by enforcing cumulative cost budgets per unit
 * and per rolling time window, using actual recorded costs from the LLM task
 * outcome ledger and the bundled model cost table.
 *
 * Consumer: UOK gate-runner during post-unit verification.
 */

import { BUNDLED_COST_TABLE, lookupModelCost } from "../model-cost-table.js";
import {
	getLlmTaskOutcomeStats,
	getLlmTaskOutcomesByUnit,
	getRecentLlmTaskOutcomes,
} from "../sf-db.js";

const DEFAULT_MAX_USD_PER_UNIT = 5.0;
const DEFAULT_MAX_USD_PER_HOUR = 20.0;
const DEFAULT_HIGH_TIER_FAILURE_THRESHOLD = 2;

function isHighTierModel(modelId) {
	const cost = lookupModelCost(modelId);
	if (!cost) return false;
	// Anything >= $0.005 per 1K input tokens is considered high-tier
	return cost.inputPer1k >= 0.005;
}

function sumCostUsd(outcomes) {
	return outcomes.reduce((sum, o) => sum + (o.cost_usd ?? 0), 0);
}

function countConsecutiveFailures(outcomes) {
	let count = 0;
	for (const o of outcomes) {
		if (!o.succeeded) count++;
		else break;
	}
	return count;
}

export class CostGuardGate {
	constructor(options = {}) {
		this.id = "cost-guard";
		this.type = "policy";
		this.maxUsdPerUnit = options.maxUsdPerUnit ?? DEFAULT_MAX_USD_PER_UNIT;
		this.maxUsdPerHour = options.maxUsdPerHour ?? DEFAULT_MAX_USD_PER_HOUR;
		this.highTierFailureThreshold =
			options.highTierFailureThreshold ?? DEFAULT_HIGH_TIER_FAILURE_THRESHOLD;
	}

	/**
	 * @param {import("./contracts.js").UokContext} ctx
	 * @param {number} _attempt
	 */
	async execute(ctx, _attempt) {
		const modelId = ctx.modelId ?? "unknown";
		const unitType = ctx.unitType ?? "unknown";
		const unitId = ctx.unitId ?? "unknown";

		// 1. Check cumulative spend for this specific unit
		const unitOutcomes = getLlmTaskOutcomesByUnit(unitType, unitId, 20);
		const unitCost = sumCostUsd(unitOutcomes);
		if (unitCost >= this.maxUsdPerUnit) {
			return {
				outcome: "fail",
				failureClass: "policy",
				rationale: `Cost-Guard blocked: unit ${unitId} has consumed $${unitCost.toFixed(2)} USD (threshold $${this.maxUsdPerUnit.toFixed(2)}).`,
				findings: `Recorded ${unitOutcomes.length} outcome(s) for this unit. Cumulative cost $${unitCost.toFixed(2)}.`,
				recommendation:
					"Review unit plan for redundancy, downgrade model, or split into smaller tasks.",
			};
		}

		// 2. Check rolling 1-hour window spend across all units
		const recentOutcomes = getRecentLlmTaskOutcomes(1, 200);
		const hourCost = sumCostUsd(recentOutcomes);
		if (hourCost >= this.maxUsdPerHour) {
			return {
				outcome: "fail",
				failureClass: "policy",
				rationale: `Cost-Guard blocked: rolling 1-hour spend is $${hourCost.toFixed(2)} USD (threshold $${this.maxUsdPerHour.toFixed(2)}).`,
				findings: `Recorded ${recentOutcomes.length} outcome(s) in the last hour. Cumulative cost $${hourCost.toFixed(2)}.`,
				recommendation:
					"Pause autonomous dispatch until hourly budget resets. Review dispatch frequency or model selection.",
			};
		}

		// 3. Check high-tier model failure pattern
		if (isHighTierModel(modelId)) {
			const modelStats = getLlmTaskOutcomeStats(modelId, 24);
			const recentUnitFailures = countConsecutiveFailures(unitOutcomes);
			if (
				recentUnitFailures >= this.highTierFailureThreshold ||
				(modelStats.total >= this.highTierFailureThreshold &&
					modelStats.failed / modelStats.total >= 0.5)
			) {
				const cheaper = this._suggestCheaperAlternative(modelId);
				return {
					outcome: "fail",
					failureClass: "policy",
					rationale: `Cost-Guard blocked high-tier model ${modelId}: ${recentUnitFailures} consecutive failure(s) for this unit, or ${modelStats.failed}/${modelStats.total} failures in 24h.`,
					findings: `Unit cost $${unitCost.toFixed(2)}. 24h model failure rate ${modelStats.total > 0 ? ((modelStats.failed / modelStats.total) * 100).toFixed(0) : 0}%.`,
					recommendation: cheaper
						? `Switch to ${cheaper.id} ($${cheaper.inputPer1k}/1K tokens) to reduce burn rate while debugging.`
						: "Downgrade to a cheaper model tier before retrying.",
				};
			}
		}

		return {
			outcome: "pass",
			rationale: `Cost budget safe: unit $${unitCost.toFixed(2)}/$${this.maxUsdPerUnit.toFixed(2)}, hour $${hourCost.toFixed(2)}/$${this.maxUsdPerHour.toFixed(2)}.`,
		};
	}

	_suggestCheaperAlternative(modelId) {
		const current = lookupModelCost(modelId);
		if (!current) return null;
		const providerPrefix = modelId.includes("/")
			? modelId.split("/")[0].toLowerCase()
			: undefined;
		const bareId = modelId.includes("/") ? modelId.split("/").pop() : modelId;
		const familyPrefix = bareId.split(/[-.]/)[0]?.toLowerCase();
		const candidates = BUNDLED_COST_TABLE.filter((candidate) => {
			if (candidate.id === current.id) return false;
			if (candidate.inputPer1k >= current.inputPer1k * 0.5) return false;
			if (
				providerPrefix &&
				candidate.id.toLowerCase().startsWith(providerPrefix)
			) {
				return true;
			}
			return (
				familyPrefix !== undefined &&
				candidate.id.toLowerCase().startsWith(familyPrefix)
			);
		}).sort((a, b) => a.inputPer1k - b.inputPer1k);
		return candidates[0] ?? null;
	}
}
