import { normalizeJMESPath, searchJMESPath } from "../utils/jmespath-utils.js";
import { getLogger } from "../utils/logger.js";

//#region src/context/TemplateEngine.ts
const logger = getLogger("template-engine");
var TemplateEngine = class TemplateEngine {
	static DEFAULT_OPTIONS = {
		strict: false,
		preserveUnresolved: false
	};
	/**
	* Render a template string with context data using JMESPath
	*/
	static render(template, context, options = {}) {
		return TemplateEngine.renderInternal(template, context, options);
	}
	/**
	* Render an agent prompt with runtime-provided builtins. $-prefixed paths are
	* first resolved against `runtimeBuiltins` via a dotted-path walk; unresolved
	* $-paths fall through to the standard built-in dispatch.
	*/
	static renderPrompt(template, context, options = {}) {
		return TemplateEngine.renderInternal(template, context, options);
	}
	static renderInternal(template, context, options) {
		const opts = {
			...TemplateEngine.DEFAULT_OPTIONS,
			...options
		};
		try {
			const rendered = TemplateEngine.processVariables(template, context, opts, options.runtimeBuiltins);
			if (opts.strict && TemplateEngine.hasTemplateVariables(rendered)) {
				const unresolvedVars = TemplateEngine.extractTemplateVariables(rendered);
				throw new Error(`Unresolved template variables: ${unresolvedVars.join(", ")}`);
			}
			return rendered;
		} catch (error) {
			logger.error({
				template: template.substring(0, 100) + (template.length > 100 ? "..." : ""),
				contextKeys: Object.keys(context),
				error: error instanceof Error ? error.message : "Unknown error"
			}, "Template rendering failed");
			throw error;
		}
	}
	/**
	* Process variable substitutions {{variable.path}} using JMESPath
	*/
	static processVariables(template, context, options, runtimeBuiltins) {
		return template.replace(/\{\{([^}]+)\}\}/g, (match, path) => {
			const trimmedPath = path.trim();
			try {
				if (trimmedPath.startsWith("$")) {
					if (runtimeBuiltins) {
						const resolved = TemplateEngine.resolveRuntimeBuiltin(trimmedPath, runtimeBuiltins);
						if (resolved !== void 0) return resolved;
					}
					return TemplateEngine.processBuiltinVariable(trimmedPath);
				}
				const normalizedPath = normalizeJMESPath(trimmedPath);
				const result = searchJMESPath(context, normalizedPath);
				if (result === void 0 || result === null) {
					if (options.strict) throw new Error(`Template variable '${trimmedPath}' not found in context`);
					if (options.preserveUnresolved) return match;
					if (trimmedPath.startsWith("headers.")) logger.warn({
						variable: trimmedPath,
						normalizedPath,
						availableKeys: Object.keys(context),
						headersContent: context.headers ? JSON.stringify(context.headers, null, 2) : "undefined"
					}, "Headers template variable debugging");
					else logger.warn({
						variable: trimmedPath,
						normalizedPath,
						availableKeys: Object.keys(context)
					}, "Template variable not found in context");
					return "";
				}
				if (typeof result === "object") return JSON.stringify(result);
				return String(result);
			} catch (error) {
				const errorMessage = error instanceof Error ? error.message : "Unknown error";
				const normalizedPath = normalizeJMESPath(trimmedPath);
				if (options.strict) throw new Error(`Failed to resolve template variable '${trimmedPath}' (normalized: '${normalizedPath}'): ${errorMessage}`);
				logger.error({
					variable: trimmedPath,
					normalizedPath,
					error: errorMessage
				}, "Failed to resolve template variable");
				return options.preserveUnresolved ? match : "";
			}
		});
	}
	/**
	* Walk a dotted `$`-prefix path against runtime-provided builtins. Returns
	* the stringified value if found and non-null, or undefined to signal
	* fall-through to the default built-in dispatch.
	*/
	static resolveRuntimeBuiltin(path, runtimeBuiltins) {
		const segments = path.split(".");
		let current = runtimeBuiltins;
		for (const segment of segments) {
			if (current === null || current === void 0) return;
			if (typeof current !== "object") return;
			current = current[segment];
		}
		if (current === void 0 || current === null) return;
		if (typeof current === "object") return JSON.stringify(current);
		return String(current);
	}
	/**
	* Process built-in variables like $env, etc.
	*/
	static processBuiltinVariable(variable) {
		if (variable.startsWith("$env.")) {
			const envVar = variable.substring(5);
			return process.env[envVar] || "";
		}
		logger.warn({ variable }, "Unknown built-in variable");
		return "";
	}
	/**
	* Check if template contains template variables
	*/
	static hasTemplateVariables(template) {
		return /\{\{[^}]+\}\}/.test(template);
	}
	/**
	* Extract all template variables from a template
	*/
	static extractTemplateVariables(template) {
		const variables = [];
		const matches = template.matchAll(/\{\{([^}]+)\}\}/g);
		for (const match of matches) {
			if (!match[1]) continue;
			variables.push(match[1].trim());
		}
		return [...new Set(variables)];
	}
	/**
	* Validate template syntax
	*/
	static validateTemplate(template) {
		const errors = [];
		try {
			const openBraces = (template.match(/\{\{/g) || []).length;
			const closeBraces = (template.match(/\}\}/g) || []).length;
			if (openBraces !== closeBraces) errors.push(`Unbalanced template braces: ${openBraces} opening, ${closeBraces} closing`);
			const variables = TemplateEngine.extractTemplateVariables(template);
			for (const variable of variables) if (variable.includes("{{") || variable.includes("}}")) errors.push(`Nested template syntax in variable: ${variable}`);
			return {
				valid: errors.length === 0,
				errors
			};
		} catch (error) {
			return {
				valid: false,
				errors: [`Template validation error: ${error instanceof Error ? error.message : "Unknown error"}`]
			};
		}
	}
	/**
	* Preview template rendering with sample context
	*/
	static preview(template, sampleContext, options = {}) {
		const variables = TemplateEngine.extractTemplateVariables(template);
		const errors = [];
		let rendered = "";
		try {
			rendered = TemplateEngine.render(template, sampleContext, options);
		} catch (error) {
			errors.push(error instanceof Error ? error.message : "Unknown rendering error");
			rendered = template;
		}
		return {
			rendered,
			variables,
			errors
		};
	}
};

//#endregion
export { TemplateEngine };