import { CredentialStoreType, MCPServerType, MCPTransportType } from "../types/utility.js";
import { getLogger } from "../utils/logger.js";
import { TemplateEngine } from "../context/TemplateEngine.js";
import { getCredentialStoreLookupKeyFromRetrievalParams } from "../utils/credential-store-utils.js";

//#region src/credential-stuffer/CredentialStuffer.ts
/**
* Manages credential retrieval and injection for MCP tools
* Uses CredentialStoreRegistry for credential store management
*/
var CredentialStuffer = class {
	logger;
	constructor(credentialStoreRegistry, contextResolver, logger) {
		this.credentialStoreRegistry = credentialStoreRegistry;
		this.contextResolver = contextResolver;
		this.logger = logger || getLogger("credential-stuffer");
	}
	/**
	* Retrieve credentials from credential store registry
	*/
	async getCredentials(context, storeReference, mcpType) {
		const credentialStore = this.credentialStoreRegistry.get(storeReference.credentialStoreId);
		if (!credentialStore) {
			this.logger.warn({
				tenantId: context.tenantId,
				credentialStoreId: storeReference.credentialStoreId,
				availableStores: this.credentialStoreRegistry.getIds()
			}, "Credential store not found in registry");
			return null;
		}
		const key = this.generateCredentialKey(context, storeReference, credentialStore.type);
		const credentialDataString = await credentialStore.get(key);
		if (!credentialDataString) {
			this.logger.warn({
				tenantId: context.tenantId,
				credentialStoreId: storeReference.credentialStoreId,
				lookupKey: key
			}, "No credential data found for key");
			return null;
		}
		if (credentialStore.type === CredentialStoreType.nango) try {
			const nangoCredentialData = JSON.parse(credentialDataString);
			if (mcpType === MCPServerType.nango) return {
				headers: {
					Authorization: `Bearer ${nangoCredentialData.secretKey}`,
					"provider-config-key": nangoCredentialData.providerConfigKey,
					"connection-id": nangoCredentialData.connectionId
				},
				metadata: nangoCredentialData.metadata
			};
			const headers = {};
			if (nangoCredentialData.token) headers.Authorization = `Bearer ${nangoCredentialData.token}`;
			return {
				headers,
				metadata: nangoCredentialData.metadata
			};
		} catch (parseError) {
			this.logger.error({
				tenantId: context.tenantId,
				credentialStoreId: storeReference.credentialStoreId,
				parseError: parseError instanceof Error ? parseError.message : "Unknown error"
			}, "Failed to parse credential data JSON");
			return null;
		}
		if (credentialStore.type === CredentialStoreType.keychain) try {
			const oauthTokens = JSON.parse(credentialDataString);
			if (oauthTokens.access_token) return {
				headers: { Authorization: `Bearer ${oauthTokens.access_token}` },
				metadata: {}
			};
		} catch {}
		return { headers: { Authorization: `Bearer ${credentialDataString}` } };
	}
	/**
	* Generate credential lookup key based on store type
	*/
	generateCredentialKey(context, storeReference, credentialStoreType) {
		return getCredentialStoreLookupKeyFromRetrievalParams({
			retrievalParams: storeReference.retrievalParams,
			credentialStoreType
		}) || context.tenantId;
	}
	/**
	* Get credentials from headers context
	*/
	async getCredentialsFromHeaders(credentialContext, headers) {
		const contextConfigId = credentialContext.contextConfigId;
		const conversationId = credentialContext.conversationId;
		if (!contextConfigId || !conversationId || !this.contextResolver) return null;
		const headersContext = await this.contextResolver.resolveHeaders(conversationId, contextConfigId);
		const resolvedHeaders = {};
		for (const [key, value] of Object.entries(headers)) resolvedHeaders[key] = TemplateEngine.render(value, { headers: headersContext }, { strict: true });
		return {
			headers: resolvedHeaders,
			metadata: {}
		};
	}
	/**
	* Get credential headers for MCP server configuration
	*/
	async getCredentialHeaders({ context, mcpType, storeReference, headers }) {
		let credentialsFromHeaders = null;
		if (context.contextConfigId && context.conversationId && headers) credentialsFromHeaders = await this.getCredentialsFromHeaders(context, headers);
		let credentialStoreHeaders = null;
		if (storeReference) credentialStoreHeaders = await this.getCredentials(context, storeReference, mcpType);
		if (!credentialStoreHeaders) return credentialsFromHeaders ? credentialsFromHeaders.headers : { ...headers };
		return {
			...credentialStoreHeaders.headers,
			...credentialStoreHeaders.metadata,
			...credentialsFromHeaders?.headers
		};
	}
	/**
	* Build MCP server configuration with credentials
	*/
	async buildMcpServerConfig(context, tool, storeReference, selectedTools) {
		let credentialHeaders = {};
		if (storeReference || tool.headers) credentialHeaders = await this.getCredentialHeaders({
			context,
			mcpType: tool.mcpType,
			storeReference,
			headers: tool.headers || {}
		});
		return {
			type: tool.transport?.type || MCPTransportType.streamableHttp,
			url: tool.serverUrl,
			activeTools: tool.activeTools,
			selectedTools,
			headers: credentialHeaders
		};
	}
};

//#endregion
export { CredentialStuffer };