import { getRun } from "../run-state/index.js";
import { nowIso } from "../../shared/index.js";
import { initializeRunBudget, updateRunBudget } from "./store.js";
export async function assertRunBudgetAllowsDelegation(store, runId, input = {}) {
    const state = await refreshRunBudgetEvaluation(store, runId, input);
    const evaluation = await evaluateRunBudget(store, state, input.now);
    if (evaluation.status === "blocked") {
        return { allowed: false, state, evaluation, reason: evaluation.blocking_reason ?? "SEED run budget is exhausted." };
    }
    return { allowed: true, state, evaluation };
}
export async function refreshRunBudgetEvaluation(store, runId, input = {}) {
    const current = await initializeRunBudget(store, runId, input.now);
    const evaluation = await evaluateRunBudget(store, current, input.now);
    if (evaluation.status === "ok" && !current.blocking_reason)
        return current;
    return updateRunBudget(store, runId, (state) => ({
        ...state,
        first_warning_at: state.first_warning_at ?? (evaluation.status === "warning" || evaluation.status === "blocked" ? input.now ?? nowIso() : undefined),
        blocking_reason: evaluation.status === "blocked" ? evaluation.blocking_reason : undefined,
    }));
}
export async function evaluateRunBudget(store, state, timestamp = nowIso()) {
    const run = await getRun(store, state.run_id);
    const runtimeHours = run ? Math.max(0, (safeTime(timestamp) - safeTime(run.created_at)) / 3_600_000) : 0;
    const ratios = {
        runtime: runtimeHours / state.limits.max_runtime_hours,
        child_sessions: state.usage.child_sessions / state.limits.max_child_sessions,
        model_calls: state.usage.model_calls / state.limits.max_model_calls,
    };
    const blockers = [
        ratios.runtime >= 1 ? `runtime budget exhausted (${runtimeHours.toFixed(2)}h/${state.limits.max_runtime_hours}h)` : "",
        state.usage.child_sessions >= state.limits.max_child_sessions ? `child session budget exhausted (${state.usage.child_sessions}/${state.limits.max_child_sessions})` : "",
        state.usage.model_calls >= state.limits.max_model_calls ? `model call budget exhausted (${state.usage.model_calls}/${state.limits.max_model_calls})` : "",
    ].filter(Boolean);
    if (blockers.length)
        return { status: "blocked", warnings: [], blocking_reason: blockers.join("; "), ratios };
    const warnings = [
        ratios.runtime >= state.limits.warn_ratio ? `runtime is ${(ratios.runtime * 100).toFixed(0)}% of budget` : "",
        ratios.child_sessions >= state.limits.warn_ratio ? `child sessions are ${state.usage.child_sessions}/${state.limits.max_child_sessions}` : "",
        ratios.model_calls >= state.limits.warn_ratio ? `model calls are ${state.usage.model_calls}/${state.limits.max_model_calls}` : "",
        ...contextWarnings(store, state),
    ].filter(Boolean);
    return { status: warnings.length ? "warning" : "ok", warnings, ratios };
}
export function formatRunBudgetStatus(state, evaluation) {
    const tokenTotal = Object.values(state.usage.tokens_by_model).reduce((sum, usage) => sum + usage.total, 0);
    const warning = evaluation.status === "blocked"
        ? `blocked: ${evaluation.blocking_reason}`
        : evaluation.warnings.length
            ? `warning: ${evaluation.warnings.join("; ")}`
            : "ok";
    return [
        `- status: ${warning}`,
        `- model calls: ${state.usage.model_calls}/${state.limits.max_model_calls}`,
        `- child sessions: ${state.usage.child_sessions}/${state.limits.max_child_sessions}`,
        `- token total: ${tokenTotal}`,
        `- context injected chars: ${state.usage.context.injected_chars_total}`,
        `- context duplicate refs: ${Object.entries(state.usage.context.duplicate_bundle_injections).filter(([, count]) => count > 1).length}`,
        `- first warning: ${state.first_warning_at ?? "(none)"}`,
    ].join("\n");
}
function contextWarnings(store, state) {
    const threshold = store.config.context_policy.duplicate_bundle_warning_threshold;
    return Object.entries(state.usage.context.duplicate_bundle_injections)
        .filter(([, count]) => count >= threshold)
        .slice(0, 5)
        .map(([bundleId, count]) => `context bundle ${bundleId} injected ${count} times`);
}
function safeTime(value) {
    const parsed = Date.parse(value);
    return Number.isFinite(parsed) ? parsed : 0;
}
//# sourceMappingURL=checks.js.map