// @crash-shield-ignore-file — config/cache reader for Planu-controlled JSON; writer is this codebase, shape guaranteed by build/seed.
// engine/ai-cost-estimator/model-pricing.ts — Loads AI model pricing from config JSON.
// Provides model lookup, cost calculation, and pricing config access.
import { readFile } from 'node:fs/promises';
import { fileURLToPath } from 'node:url';
import { dirname, join } from 'node:path';
// ---------------------------------------------------------------------------
// Config loading
// ---------------------------------------------------------------------------
const CONFIG_FILENAME = 'ai-model-pricing.json';
/** Resolve the path to the config file relative to this module. */
function resolveConfigPath() {
    const __filename = fileURLToPath(import.meta.url);
    const __dirname = dirname(__filename);
    return join(__dirname, '../../config', CONFIG_FILENAME);
}
/** Cache to avoid repeated disk reads within a process lifetime. */
let cachedConfig = null;
/**
 * Loads the AI model pricing configuration from disk.
 * Results are cached after the first load.
 */
export async function loadPricingConfig() {
    if (cachedConfig !== null) {
        return cachedConfig;
    }
    const configPath = resolveConfigPath();
    try {
        const raw = await readFile(configPath, 'utf-8');
        cachedConfig = JSON.parse(raw);
        return cachedConfig;
        /* v8 ignore start */
    }
    catch (err) {
        const reason = err instanceof Error ? err.message : String(err);
        throw new Error(`[Planu] Failed to load AI model pricing config from ${configPath}: ${reason}`, { cause: err });
    }
    /* v8 ignore stop */
}
/** Clears the in-memory cache (used in tests). */
export function clearPricingCache() {
    cachedConfig = null;
}
// ---------------------------------------------------------------------------
// Model lookup
// ---------------------------------------------------------------------------
/**
 * Returns all configured AI models.
 */
export async function getAllModels() {
    const config = await loadPricingConfig();
    return config.models;
}
/**
 * Finds a model by its ID. Returns null if not found.
 */
export async function findModel(modelId) {
    const models = await getAllModels();
    return models.find((m) => m.id === modelId) ?? null;
}
// ---------------------------------------------------------------------------
// Cost calculation
// ---------------------------------------------------------------------------
/**
 * Calculates the estimated cost in USD for a given model and token counts.
 *
 * Formula: (inputTokens / 1_000_000 × inputPrice) + (outputTokens / 1_000_000 × outputPrice)
 */
export function calculateCost(model, inputTokens, outputTokens) {
    const inputCost = (inputTokens / 1_000_000) * model.inputPricePerMillion;
    const outputCost = (outputTokens / 1_000_000) * model.outputPricePerMillion;
    return inputCost + outputCost;
}
/**
 * Returns the number of agent turns needed to generate the given LOC count.
 */
export function calculateAgentTurns(model, locToGenerate) {
    if (model.avgThroughputLOCPerTurn <= 0) {
        return 1;
    }
    return Math.ceil(locToGenerate / model.avgThroughputLOCPerTurn);
}
// ---------------------------------------------------------------------------
// Price staleness check
// ---------------------------------------------------------------------------
const STALE_DAYS = 30;
/**
 * Returns true if the pricing config is older than STALE_DAYS days.
 */
export function isPricingStale(lastUpdated) {
    const updatedDate = new Date(lastUpdated);
    const now = new Date();
    const diffMs = now.getTime() - updatedDate.getTime();
    const diffDays = diffMs / (1000 * 60 * 60 * 24);
    return diffDays > STALE_DAYS;
}
//# sourceMappingURL=model-pricing.js.map