import { calculateCost } from "../utils/costs.js";
import { tryRequire } from "../utils/resolve-module.js";
import { StreamingAccumulator } from "../utils/streaming.js";
import { BaseAIProvider, applySessionContext, contextFields } from "./base.js";

//#region src/providers/mistral.ts
const _resolved = tryRequire("@mistralai/mistralai");
const MISTRAL_AVAILABLE = _resolved != null;
const _MistralModule = _resolved;
var Mistral = class extends BaseAIProvider {
	_client;
	chat;
	constructor(options) {
		super({
			amplitude: options.amplitude,
			privacyConfig: options.privacyConfig,
			providerName: "mistral"
		});
		if (options.client != null) {
			this._client = options.client;
			this.chat = new WrappedChat(this._client, this.trackFn());
			return;
		}
		const mod = options.mistralModule ?? _MistralModule;
		if (mod == null) throw new Error("@mistralai/mistralai package is required. Install it with: npm install @mistralai/mistralai — or pass the module directly via the mistralModule option.");
		const MistralSDK = mod.Mistral ?? mod.MistralClient ?? mod.default;
		const clientOpts = {};
		if (options.apiKey) clientOpts.apiKey = options.apiKey;
		this._client = new MistralSDK(clientOpts);
		this.chat = new WrappedChat(this._client, this.trackFn());
	}
	get client() {
		return this._client;
	}
};
var WrappedChat = class {
	_client;
	_trackFn;
	constructor(client, trackFn) {
		this._client = client;
		this._trackFn = typeof trackFn === "function" ? trackFn : trackFn.trackFn();
	}
	async complete(params) {
		const chat = this._client.chat;
		const completeFn = chat.complete;
		const startTime = performance.now();
		const ctx = applySessionContext();
		try {
			const response = await completeFn.call(chat, params);
			if ((params.stream === true || chat.stream != null) && _isAsyncIterable(response)) return this._wrapStream(response, params, ctx);
			const latencyMs = performance.now() - startTime;
			const resp = response;
			const choice = resp.choices?.[0];
			const usage = resp.usage;
			const modelName = String(resp.model ?? params.model ?? "unknown");
			const toolCalls = (choice?.message)?.tool_calls;
			let costUsd = null;
			if (usage?.prompt_tokens != null && usage?.completion_tokens != null) try {
				costUsd = calculateCost({
					modelName,
					inputTokens: usage.prompt_tokens,
					outputTokens: usage.completion_tokens,
					defaultProvider: "mistral"
				});
			} catch {}
			this._trackFn({
				...contextFields(ctx),
				modelName,
				provider: "mistral",
				responseContent: extractMistralContent(choice?.message?.content),
				latencyMs,
				inputTokens: usage?.prompt_tokens,
				outputTokens: usage?.completion_tokens,
				totalTokens: usage?.total_tokens,
				totalCostUsd: costUsd,
				finishReason: choice?.finish_reason,
				toolCalls: toolCalls ?? void 0,
				toolDefinitions: extractMistralToolDefinitions(params),
				systemPrompt: extractMistralSystemPrompt(params),
				temperature: params.temperature,
				topP: params.top_p,
				maxOutputTokens: params.max_tokens,
				isStreaming: false
			});
			return response;
		} catch (error) {
			const latencyMs = performance.now() - startTime;
			this._trackFn({
				...contextFields(ctx),
				modelName: String(params.model ?? "unknown"),
				provider: "mistral",
				responseContent: "",
				latencyMs,
				isError: true,
				errorMessage: error instanceof Error ? error.message : String(error)
			});
			throw error;
		}
	}
	async stream(params) {
		const ctx = applySessionContext();
		const startTime = performance.now();
		try {
			const chat = this._client.chat;
			const streamFn = chat.stream;
			if (typeof streamFn !== "function") throw new Error("Mistral SDK does not expose chat.stream");
			const response = await streamFn.call(chat, params);
			if (!_isAsyncIterable(response)) throw new Error("Mistral stream response is not AsyncIterable");
			return this._wrapStream(response, params, ctx);
		} catch (error) {
			this._trackFn({
				...contextFields(ctx),
				modelName: String(params.model ?? "unknown"),
				provider: "mistral",
				responseContent: "",
				latencyMs: performance.now() - startTime,
				isError: true,
				errorMessage: error instanceof Error ? error.message : String(error),
				isStreaming: true
			});
			throw error;
		}
	}
	async *_wrapStream(stream, params, sessionCtx) {
		const accumulator = new StreamingAccumulator();
		accumulator.model = String(params.model ?? "unknown");
		try {
			for await (const chunk of stream) {
				const c = chunk;
				const choices = c.choices;
				const delta = choices?.[0]?.delta;
				const message = choices?.[0]?.message;
				const content = delta?.content ?? message?.content;
				if (typeof content === "string" && content.length > 0) accumulator.addContent(content);
				const toolCalls = delta?.tool_calls ?? message?.tool_calls;
				if (Array.isArray(toolCalls)) for (const call of toolCalls) {
					const idx = call.index;
					const id = call.id;
					const fn = call.function;
					if (idx != null && id && fn?.name != null) accumulator.setToolCallAt(idx, {
						type: "function",
						id,
						function: {
							name: fn.name,
							arguments: fn.arguments ?? ""
						}
					});
					else if (idx != null && fn?.arguments) accumulator.appendToolCallArgs(idx, fn.arguments);
					else accumulator.addToolCall(call);
				}
				const finishReason = choices?.[0]?.finish_reason;
				if (finishReason != null) accumulator.finishReason = String(finishReason);
				const usage = c.usage;
				accumulator.setUsage({
					inputTokens: usage?.prompt_tokens,
					outputTokens: usage?.completion_tokens,
					totalTokens: usage?.total_tokens
				});
				yield chunk;
			}
		} catch (error) {
			accumulator.setError(error instanceof Error ? error.message : String(error));
			throw error;
		} finally {
			const state = accumulator.getState();
			const modelName = String(accumulator.model ?? params.model ?? "unknown");
			let costUsd = null;
			if (state.inputTokens != null && state.outputTokens != null) try {
				costUsd = calculateCost({
					modelName,
					inputTokens: state.inputTokens,
					outputTokens: state.outputTokens,
					defaultProvider: "mistral"
				});
			} catch {}
			this._trackFn({
				...contextFields(sessionCtx),
				modelName,
				provider: "mistral",
				responseContent: state.content,
				latencyMs: accumulator.elapsedMs,
				inputTokens: state.inputTokens,
				outputTokens: state.outputTokens,
				totalTokens: state.totalTokens,
				totalCostUsd: costUsd,
				finishReason: state.finishReason,
				toolCalls: state.toolCalls.length > 0 ? state.toolCalls : void 0,
				toolDefinitions: extractMistralToolDefinitions(params),
				systemPrompt: extractMistralSystemPrompt(params),
				temperature: params.temperature,
				topP: params.top_p,
				maxOutputTokens: params.max_tokens,
				providerTtfbMs: state.ttfbMs,
				isStreaming: true,
				isError: state.isError,
				errorMessage: state.errorMessage
			});
		}
	}
};
function extractMistralContent(content) {
	if (typeof content === "string") return content;
	if (content == null) return "";
	if (Array.isArray(content)) return content.map((chunk) => {
		if (typeof chunk === "string") return chunk;
		if (typeof chunk === "object" && chunk != null) return String(chunk.text ?? "");
		return "";
	}).filter(Boolean).join("");
	return String(content);
}
function extractMistralSystemPrompt(params) {
	const messages = params.messages;
	if (!Array.isArray(messages)) return void 0;
	const systemMessage = messages.find((m) => m.role === "system");
	return typeof systemMessage?.content === "string" ? systemMessage.content : void 0;
}
function extractMistralToolDefinitions(params) {
	const tools = params.tools;
	return Array.isArray(tools) && tools.length > 0 ? tools : void 0;
}
function _isAsyncIterable(value) {
	return value != null && typeof value[Symbol.asyncIterator] === "function";
}

//#endregion
export { MISTRAL_AVAILABLE, Mistral, WrappedChat, _MistralModule };
//# sourceMappingURL=mistral.js.map