import { ContextConfigApiUpdateSchema } from "../validation/schemas.js";
import { getLogger } from "../utils/logger.js";
import { convertZodToJsonSchema } from "../utils/schema-conversion.js";
import { z } from "@hono/zod-openapi";

//#region src/context/ContextConfig.ts
const logger = getLogger("context-config");
var HeadersSchemaBuilder = class {
	schema;
	constructor(options) {
		this.schema = options.schema;
	}
	/** Template function for headers paths with type-safe autocomplete */
	toTemplate(path) {
		return `{{headers.${path}}}`;
	}
	getSchema() {
		return this.schema;
	}
	getJsonSchema() {
		return convertZodToJsonSchema(this.schema);
	}
};
var ContextConfigBuilder = class {
	config;
	baseURL;
	tenantId;
	projectId;
	agentId;
	constructor(options) {
		this.tenantId = options.tenantId || "default";
		this.projectId = options.projectId || "default";
		this.agentId = options.agentId || "default";
		this.baseURL = process.env.INKEEP_AGENTS_API_URL || "http://localhost:3002";
		let headers$1;
		if (options.headers) {
			const actualSchema = options.headers instanceof HeadersSchemaBuilder ? options.headers.getSchema() : options.headers;
			logger.debug({ headers: options.headers }, "Converting headers schema to JSON Schema for database storage");
			headers$1 = convertZodToJsonSchema(actualSchema);
		}
		const processedContextVariables = {};
		if (options.contextVariables) for (const [key, definition] of Object.entries(options.contextVariables)) {
			const { credentialReference, ...rest } = definition;
			const credentialReferenceId = credentialReference?.id || rest.credentialReferenceId;
			processedContextVariables[key] = {
				...rest,
				responseSchema: convertZodToJsonSchema(definition.responseSchema)
			};
			if (credentialReferenceId !== void 0) processedContextVariables[key].credentialReferenceId = credentialReferenceId;
			logger.debug({
				contextVariableKey: key,
				originalSchema: definition.responseSchema,
				credentialReferenceId
			}, "Converting contextVariable responseSchema to JSON Schema for database storage");
		}
		if (!options.id) throw new Error("contextConfig requires an explicit id field");
		this.config = {
			id: options.id,
			tenantId: this.tenantId,
			projectId: this.projectId,
			headersSchema: headers$1,
			contextVariables: processedContextVariables
		};
		logger.info({
			contextConfigId: this.config.id,
			tenantId: this.tenantId
		}, "ContextConfig builder initialized");
	}
	/**
	* Set the context (tenantId, projectId, agentId) for this context config
	* Called by agent.setConfig() when the agent is configured
	*/
	setContext(tenantId, projectId, agentId, baseURL) {
		this.tenantId = tenantId;
		this.projectId = projectId;
		this.agentId = agentId;
		this.baseURL = baseURL;
		this.config.tenantId = tenantId;
		this.config.projectId = projectId;
		this.config.agentId = agentId;
		logger.info({
			contextConfigId: this.config.id,
			tenantId: this.tenantId,
			projectId: this.projectId,
			agentId: this.agentId
		}, "ContextConfig context updated");
	}
	/**
	* Convert the builder to a plain object for database operations
	*/
	toObject() {
		return {
			id: this.getId(),
			tenantId: this.tenantId,
			projectId: this.projectId,
			agentId: this.agentId,
			headersSchema: this.getHeadersSchema(),
			contextVariables: this.getContextVariables(),
			createdAt: (/* @__PURE__ */ new Date()).toISOString(),
			updatedAt: (/* @__PURE__ */ new Date()).toISOString()
		};
	}
	getId() {
		if (!this.config.id) throw new Error("Context config ID is not set");
		return this.config.id;
	}
	getHeadersSchema() {
		return this.config.headersSchema || null;
	}
	getContextVariables() {
		return this.config.contextVariables || {};
	}
	withHeadersSchema(schema) {
		this.config.headersSchema = schema;
		return this;
	}
	/** 4) The function you ship: path autocomplete + validation, returns {{path}} */
	toTemplate(path) {
		return `{{${path}}}`;
	}
	validate() {
		try {
			if ("headers" in (this.config.contextVariables || {})) return {
				valid: false,
				errors: ["The key 'headers' is reserved for the headers context and cannot be used in contextVariables"]
			};
			ContextConfigApiUpdateSchema.parse({
				id: this.config.id,
				headersSchema: this.config.headersSchema,
				contextVariables: this.config.contextVariables
			});
			return {
				valid: true,
				errors: []
			};
		} catch (error) {
			if (error instanceof z.ZodError) return {
				valid: false,
				errors: error.issues.map((e) => `${e.path.join(".")}: ${e.message}`)
			};
			return {
				valid: false,
				errors: ["Unknown validation error"]
			};
		}
	}
	async init() {
		const validation = this.validate();
		if (!validation.valid) throw new Error(`Context config validation failed: ${validation.errors.join(", ")}`);
		try {
			await this.upsertContextConfig();
			logger.info({ contextConfigId: this.getId() }, "Context config initialized successfully");
		} catch (error) {
			logger.error({
				contextConfigId: this.getId(),
				error: error instanceof Error ? error.message : "Unknown error"
			}, "Failed to initialize context config");
			throw error;
		}
	}
	async upsertContextConfig() {
		const configData = {
			id: this.getId(),
			headersSchema: this.getHeadersSchema(),
			contextVariables: this.getContextVariables()
		};
		try {
			const updateResponse = await fetch(`${this.baseURL}/manage/tenants/${this.tenantId}/projects/${this.projectId}/agent/${this.agentId}/context-configs/${this.getId()}`, {
				method: "PUT",
				headers: { "Content-Type": "application/json" },
				body: JSON.stringify(configData)
			});
			if (updateResponse.ok) {
				logger.info({ contextConfigId: this.getId() }, "Context config updated successfully");
				return;
			}
			if (updateResponse.status === 404) {
				logger.info({ contextConfigId: this.getId() }, "Context config not found, creating new config");
				const createResponse = await fetch(`${this.baseURL}/manage/tenants/${this.tenantId}/projects/${this.projectId}/agent/${this.agentId}/context-configs`, {
					method: "POST",
					headers: { "Content-Type": "application/json" },
					body: JSON.stringify(configData)
				});
				if (!createResponse.ok) {
					const errorData$1 = await this.parseErrorResponse(createResponse);
					throw new Error(`Failed to create context config (${createResponse.status}): ${errorData$1.message || errorData$1.error || "Unknown error"}`);
				}
				logger.info({ contextConfigId: this.getId() }, "Context config created successfully");
				return;
			}
			const errorData = await this.parseErrorResponse(updateResponse);
			throw new Error(`Failed to update context config (${updateResponse.status}): ${errorData.message || errorData.error || "Unknown error"}`);
		} catch (error) {
			if (error instanceof Error) throw error;
			throw new Error(`Network error while upserting context config: ${String(error)}`);
		}
	}
	async parseErrorResponse(response) {
		try {
			if ((response.headers?.get("content-type"))?.includes("application/json")) return await response.json();
			return { error: await response.text() || `HTTP ${response.status} ${response.statusText}` };
		} catch (_error) {
			return { error: `HTTP ${response.status} ${response.statusText}` };
		}
	}
};
function contextConfig(options) {
	return new ContextConfigBuilder(options);
}
function headers(options) {
	return new HeadersSchemaBuilder(options);
}
function fetchDefinition(options) {
	const fetchConfig = options.fetchConfig;
	const result = {
		id: options.id,
		trigger: options.trigger,
		fetchConfig: { url: fetchConfig.url },
		responseSchema: options.responseSchema
	};
	if (options.name !== void 0) result.name = options.name;
	if (options.defaultValue !== void 0) result.defaultValue = options.defaultValue;
	if (fetchConfig.method !== void 0) result.fetchConfig.method = fetchConfig.method;
	if (fetchConfig.headers !== void 0) result.fetchConfig.headers = fetchConfig.headers;
	if (fetchConfig.transform !== void 0) result.fetchConfig.transform = fetchConfig.transform;
	if (fetchConfig.body !== void 0) result.fetchConfig.body = fetchConfig.body;
	if (fetchConfig.timeout !== void 0) result.fetchConfig.timeout = fetchConfig.timeout;
	if (fetchConfig.requiredToFetch !== void 0) result.fetchConfig.requiredToFetch = fetchConfig.requiredToFetch;
	if (options.credentialReference?.id !== void 0) result.credentialReferenceId = options.credentialReference.id;
	return result;
}

//#endregion
export { ContextConfigBuilder, HeadersSchemaBuilder, contextConfig, fetchDefinition, headers };