import { getLogger } from "../../../logger.js";
import jmespath from "jmespath";

//#region src/domains/run/utils/SchemaProcessor.ts
/**
* Centralized schema processing and validation utilities
*/
var SchemaProcessor = class SchemaProcessor {
	static logger = getLogger("SchemaProcessor");
	/**
	* Transform complex schema types to strings for JMESPath compatibility
	*/
	static transformSchemaForJMESPath(schema) {
		if (!schema || typeof schema !== "object") return schema;
		const transform = (obj) => {
			if (Array.isArray(obj)) return obj.map(transform);
			if (obj && typeof obj === "object") {
				const result = {};
				for (const [key, value] of Object.entries(obj)) if (key === "type" && typeof value === "string") result[key] = value === "string" ? "string" : "string";
				else result[key] = transform(value);
				return result;
			}
			return obj;
		};
		return transform(schema);
	}
	/**
	* Validate if a selector looks like a valid JMESPath expression
	*/
	static validateJMESPathSelector(selector) {
		if (SchemaProcessor.isLiteralValue(selector)) return {
			isLiteral: true,
			isValidSelector: false
		};
		if (SchemaProcessor.looksLikeJMESPath(selector)) return {
			isLiteral: false,
			isValidSelector: true
		};
		return {
			isLiteral: false,
			isValidSelector: false
		};
	}
	/**
	* Check if a selector looks like a JMESPath expression
	*/
	static looksLikeJMESPath(selector) {
		if (/^[a-zA-Z_][a-zA-Z0-9_]*\.[a-zA-Z_][a-zA-Z0-9_]*$/.test(selector)) return true;
		if (/^[a-zA-Z_][a-zA-Z0-9_]*(\.[a-zA-Z_][a-zA-Z0-9_]*)+$/.test(selector)) return true;
		if (/\[\d+\]/.test(selector) || /\[\*\]/.test(selector)) return true;
		if (/\[.*?\]/.test(selector) && /[=<>!]/.test(selector)) return true;
		if (selector.includes("|")) return true;
		return false;
	}
	/**
	* Check if a selector appears to be a literal value rather than a JMESPath expression
	*/
	static isLiteralValue(selector) {
		if (SchemaProcessor.looksLikeJMESPath(selector)) return false;
		if (/^https?:\/\//.test(selector)) return true;
		if (/^[0-9]+$/.test(selector)) return true;
		if (selector.includes(" ") && !selector.includes("[")) return true;
		if (/^[a-zA-Z0-9\s\-_,;:!?.'"+()]+$/.test(selector) && selector.length > 20) return true;
		return false;
	}
	/**
	* Safely extract data using JMESPath with validation
	*/
	static safeJMESPathSearch(data, selector, fallback = null) {
		try {
			const validation = SchemaProcessor.validateJMESPathSelector(selector);
			if (validation.isLiteral) {
				SchemaProcessor.logger.debug({ selector }, "Selector appears to be literal value, returning as-is");
				return selector;
			}
			if (!validation.isValidSelector) {
				SchemaProcessor.logger.warn({ selector }, "Selector does not appear to be valid JMESPath");
				return fallback;
			}
			return jmespath.search(data, selector) || fallback;
		} catch (error) {
			SchemaProcessor.logger.warn({
				selector,
				error: error instanceof Error ? error.message : String(error)
			}, "JMESPath search failed");
			return fallback;
		}
	}
	/**
	* Validate schema structure for artifact components
	*/
	static validateArtifactSchema(schema) {
		const errors = [];
		if (!schema || typeof schema !== "object") {
			errors.push("Schema must be an object");
			return {
				isValid: false,
				errors
			};
		}
		if (!schema.type || schema.type !== "object") errors.push("Schema must have type \"object\"");
		if (!schema.properties || typeof schema.properties !== "object") errors.push("Schema must have properties object");
		const transformedSchema = SchemaProcessor.transformSchemaForJMESPath(schema);
		return {
			isValid: errors.length === 0,
			errors,
			transformedSchema
		};
	}
	/**
	* Extract property value with proper type conversion and validation
	*/
	static extractPropertyValue(data, _propName, selector, expectedType) {
		const value = SchemaProcessor.safeJMESPathSearch(data, selector);
		if (value === null || value === void 0) return null;
		if (expectedType) switch (expectedType) {
			case "string": return String(value);
			case "number": {
				const num = Number(value);
				return Number.isNaN(num) ? null : num;
			}
			case "boolean": return Boolean(value);
			case "array": return Array.isArray(value) ? value : [value];
			default: return value;
		}
		return value;
	}
	/**
	* Enhance schema with JMESPath guidance for artifact component schemas
	* Transforms all schema types to string selectors with helpful descriptions
	*/
	static enhanceSchemaWithJMESPathGuidance(schema) {
		if (!schema || typeof schema !== "object") return schema || {};
		const transformToSelectorSchema = (obj, path = "") => {
			if (!obj || typeof obj !== "object") return obj;
			if (obj.type === "array") {
				obj.items?.description;
				const arrayDescription = obj.description || "array data";
				path.includes("content");
				return {
					type: "string",
					description: `🎯 ARRAY SELECTOR: Provide JMESPath selector for ${arrayDescription}. RELATIVE to base selector - this will be applied to the item selected by base_selector. Example: "content.blocks" or "items" (NOT absolute paths like "result.content.blocks")`
				};
			}
			if (obj.type === "object" && !obj.properties) return {
				type: "string",
				description: `🎯 OBJECT SELECTOR: Provide JMESPath selector for ${obj.description || "object data"}. RELATIVE to base selector - this will be applied to the item selected by base_selector. Example: "metadata" or "spec.details" (NOT absolute paths)`
			};
			if (obj.type === "object" && obj.properties) {
				const transformedProperties = {};
				Object.entries(obj.properties).forEach(([propertyName, property]) => {
					transformedProperties[propertyName] = transformToSelectorSchema(property, path ? `${path}.${propertyName}` : propertyName);
				});
				return {
					type: "object",
					properties: transformedProperties,
					required: obj.required || [],
					description: `${obj.description || "Object containing JMESPath selectors"} - Each property should be a selector RELATIVE to the base_selector`
				};
			}
			if ([
				"string",
				"number",
				"boolean"
			].includes(obj.type)) {
				const originalDescription = obj.description || `${obj.type} value`;
				return {
					type: "string",
					description: `🎯 FIELD SELECTOR: Provide JMESPath selector for ${originalDescription}. RELATIVE to base selector (e.g., "title", "metadata.category", "properties.value"). For nested data: use field paths like "content.details", "attributes.data", "specifications.info". NOT absolute paths and NOT literal values like "${originalDescription}". The base_selector finds the item, this selector extracts the field FROM that item.`
				};
			}
			return {
				type: "string",
				description: `🎯 SELECTOR: Provide JMESPath selector RELATIVE to base selector. Example: "fieldName" or "nested.path" (NOT absolute paths)`
			};
		};
		return transformToSelectorSchema(schema);
	}
};

//#endregion
export { SchemaProcessor };