import { inferProviderFromModel, tryInferProviderFromModel } from "./providers.js";
import { calcPrice, updatePrices } from "@pydantic/genai-prices";

//#region src/utils/costs.ts
/**
* Cost calculation utilities.
*
* Uses the genai-prices package (npm: @pydantic/genai-prices) for pricing.
* Static import ensures bundlers (Next.js, Vercel, Turbopack) properly
* resolve the module instead of silently failing via createRequire().
*/
let _livePricesEnabled = false;
/**
* Opt in to background price updates from the genai-prices GitHub repo.
*
* Call once at application startup (e.g. after `AmplitudeAI` init) to fetch
* the latest pricing data periodically. This ensures new model pricing is
* available within days of being added to the genai-prices repository,
* instead of waiting for an npm package release.
*
* This makes outbound HTTPS requests to raw.githubusercontent.com.
* Only enable in environments where outbound network access is permitted.
*
* @param intervalMs - refresh interval in milliseconds (default: 1 hour)
*/
function enableLivePriceUpdates(intervalMs = 36e5) {
	if (_livePricesEnabled) return;
	_livePricesEnabled = true;
	if (typeof updatePrices !== "function") return;
	const doUpdate = () => {
		try {
			updatePrices(async ({ remoteDataUrl, setProviderData }) => {
				try {
					const resp = await fetch(remoteDataUrl);
					if (resp.ok) setProviderData(await resp.json());
				} catch {}
			});
		} catch {}
	};
	doUpdate();
	setInterval(doUpdate, intervalMs).unref?.();
}
function stripProviderPrefix(modelName) {
	const colonIdx = modelName.indexOf(":");
	if (colonIdx < 0) return modelName;
	if (modelName.slice(0, colonIdx).includes(".")) return modelName;
	return modelName.slice(colonIdx + 1);
}
/**
* Infer the provider name from a model name.
* Delegates to the canonical implementation in utils/providers.ts.
*/
const inferProvider = inferProviderFromModel;
function normalizeProviderForGenaiPrices(provider) {
	if (provider === "gemini") return "google";
	return provider;
}
/**
* Generate candidate (modelRef, providerId) pairs for price lookup.
*
* For Bedrock/AWS models, uses a **generalized** dot-prefix stripping strategy
* instead of enumerating known regions or vendors.  Bedrock model IDs follow
* `[region.][vendor.]model-name[-version]` — we progressively strip
* dot-separated prefixes and try each variant with and without provider,
* plus `regional.` / `global.` prefixes that genai-prices uses.
*
* This approach is forward-compatible: new AWS regions and Bedrock vendors
* work automatically without code changes.
*/
function getGenaiPriceLookupCandidates(modelName, defaultProvider) {
	const stripped = stripProviderPrefix(modelName);
	const inferred = defaultProvider ?? tryInferProviderFromModel(stripped);
	const isBedrock = inferred === "bedrock" || defaultProvider === "bedrock" || modelName.startsWith("bedrock:");
	const providerId = isBedrock ? "aws" : normalizeProviderForGenaiPrices(inferred);
	const candidates = [{
		model: stripped,
		providerId
	}];
	if (isBedrock) candidates.push({
		model: stripped,
		providerId: void 0
	});
	if (stripped.includes(".")) {
		const parts = stripped.split(".");
		for (let i = 1; i < parts.length; i++) {
			const sub = parts.slice(i).join(".");
			candidates.push({
				model: sub,
				providerId
			});
			candidates.push({ model: sub });
		}
		if (isBedrock) {
			let vendorModel = stripped;
			const firstSeg = parts[0];
			if (firstSeg !== "regional" && firstSeg !== "global" && parts.length > 2) vendorModel = parts.slice(1).join(".");
			if (!vendorModel.startsWith("regional.") && !vendorModel.startsWith("global.")) {
				candidates.push({ model: `regional.${vendorModel}` });
				candidates.push({ model: `global.${vendorModel}` });
			}
		}
	}
	const seen = /* @__PURE__ */ new Set();
	return candidates.filter((c) => {
		const key = `${c.model}::${c.providerId ?? ""}`;
		if (seen.has(key)) return false;
		seen.add(key);
		return true;
	});
}
function safeInt(value) {
	if (typeof value === "number" && !Number.isNaN(value)) return Math.round(value);
	return 0;
}
/**
* Calculate cost for an LLM call using genai-prices.
*
* IMPORTANT CONTRACT:
* - `inputTokens` MUST be the TOTAL input token count (including cached tokens).
*    For Anthropic: raw input_tokens + cache_read + cache_creation.
*    For OpenAI: prompt_tokens already includes cached_tokens.
* - `outputTokens` MUST be the TOTAL output token count (including reasoning tokens).
*    For OpenAI: completion_tokens already includes reasoning_tokens.
*    Do NOT pass reasoning tokens separately and then add them here.
* - `cacheReadInputTokens` and `cacheCreationInputTokens` are SUBSETS of inputTokens,
*    used only for differential pricing (cached tokens are cheaper).
* - `reasoningTokens` is IGNORED for cost calculation — it exists only for backward
*    compatibility. Reasoning tokens are already included in outputTokens.
*/
function calculateCost(options) {
	const { modelName, inputTokens, outputTokens, cacheReadInputTokens = 0, cacheCreationInputTokens = 0, defaultProvider } = options;
	try {
		const usage = {
			input_tokens: safeInt(inputTokens),
			output_tokens: safeInt(outputTokens),
			cache_read_tokens: safeInt(cacheReadInputTokens),
			cache_write_tokens: safeInt(cacheCreationInputTokens)
		};
		const candidates = getGenaiPriceLookupCandidates(modelName, defaultProvider);
		for (const { model, providerId } of candidates) {
			const opts = {};
			if (providerId) opts.providerId = providerId;
			const result = calcPrice(usage, model, Object.keys(opts).length > 0 ? opts : void 0);
			if (result?.total_price != null && result.total_price > 0) return result.total_price;
		}
	} catch {}
	return 0;
}

//#endregion
export { calculateCost, enableLivePriceUpdates, getGenaiPriceLookupCandidates, inferProvider, stripProviderPrefix };
//# sourceMappingURL=costs.js.map