/**
 * Object Transformation Utilities
 * Centralizes repeated object transformation patterns to improve code reuse and maintainability
 */
import { logger } from "./logger.js";
import { inlineJsonSchema } from "./schemaConversion.js";
// ============================================================================
// TOOL EXECUTION TRANSFORMATIONS
// ============================================================================
/**
 * Transform tool execution results from AI SDK format to NeuroLink GenerateResult format
 * Handles both single execution and array formats with robust type checking
 *
 * @param toolExecutions - Array of tool execution results from AI SDK (optional)
 * @returns Array of standardized tool execution objects with name, input, output, and duration
 *
 * @example
 * ```typescript
 * const executions = transformToolExecutions([
 *   { name: "calculator", input: { a: 5, b: 3 }, output: 8, duration: 150 }
 * ]);
 * // Returns: [{ name: "calculator", input: { a: 5, b: 3 }, output: 8, duration: 150 }]
 * ```
 */
export function transformToolExecutions(toolExecutions) {
    if (!toolExecutions || !Array.isArray(toolExecutions)) {
        return [];
    }
    return toolExecutions.map((te, index) => {
        const teRecord = te;
        // Enhanced tool name extraction with multiple fallback strategies
        let toolName = teRecord.name ||
            teRecord.toolName ||
            teRecord.tool ||
            "";
        // If still no name, try to extract from nested objects
        if (!toolName &&
            teRecord.toolCall &&
            typeof teRecord.toolCall === "object") {
            const toolCall = teRecord.toolCall;
            toolName =
                toolCall.name || toolCall.toolName || "";
        }
        // Last resort: use index-based fallback to avoid "Unknown Tool"
        if (!toolName) {
            toolName = `tool_execution_${index}`;
        }
        // Enhanced tool parameter extraction with structured logging
        const parameterExtractionData = {
            executionIndex: index,
            toolNameExtracted: toolName,
            primarySources: {
                hasInput: !!teRecord.input,
                hasParameters: !!teRecord.parameters,
                hasArgs: !!teRecord.args,
                inputType: typeof teRecord.input,
                parametersType: typeof teRecord.parameters,
                argsType: typeof teRecord.args,
            },
            rawRecordKeys: Object.keys(teRecord),
        };
        logger.debug("[TransformationUtils] Tool parameter extraction analysis", parameterExtractionData);
        // Enhanced input extraction
        let input = teRecord.input ||
            teRecord.parameters ||
            teRecord.args ||
            {};
        const primaryExtractionResult = {
            keysCount: Object.keys(input).length,
            keys: Object.keys(input),
            extractionSuccessful: Object.keys(input).length > 0,
            extractionSource: teRecord.input
                ? "input"
                : teRecord.parameters
                    ? "parameters"
                    : teRecord.args
                        ? "args"
                        : "empty",
        };
        logger.debug("[TransformationUtils] Primary parameter extraction result", primaryExtractionResult);
        // Extract input from nested toolCall if available
        if (Object.keys(input).length === 0 &&
            teRecord.toolCall &&
            typeof teRecord.toolCall === "object") {
            const toolCall = teRecord.toolCall;
            const nestedExtractionData = {
                reason: "Primary extraction failed, checking nested toolCall",
                nestedSources: {
                    hasInput: !!toolCall.input,
                    hasParameters: !!toolCall.parameters,
                    hasArgs: !!toolCall.args,
                },
                toolCallKeys: Object.keys(toolCall),
            };
            logger.debug("[TransformationUtils] Nested parameter extraction attempt", nestedExtractionData);
            input =
                toolCall.input ||
                    toolCall.parameters ||
                    toolCall.args ||
                    {};
            const nestedExtractionResult = {
                keysCount: Object.keys(input).length,
                keys: Object.keys(input),
                extractionSuccessful: Object.keys(input).length > 0,
                extractionSource: toolCall.input
                    ? "toolCall.input"
                    : toolCall.parameters
                        ? "toolCall.parameters"
                        : toolCall.args
                            ? "toolCall.args"
                            : "empty",
            };
            logger.debug("[TransformationUtils] Nested parameter extraction result", nestedExtractionResult);
        }
        // Target tool parameter analysis for critical tools
        if (toolName &&
            (toolName.includes("SuccessRateSRByTime") ||
                toolName.includes("juspay-analytics"))) {
            const targetToolAnalysis = {
                toolName,
                inputKeys: Object.keys(input),
                keysCount: Object.keys(input).length,
                hasStartTime: "startTime" in input,
                hasEndTime: "endTime" in input,
                startTimeValue: input.startTime || "MISSING",
                endTimeValue: input.endTime || "MISSING",
                extractionStatus: Object.keys(input).length === 0 ? "FAILED" : "SUCCESS",
            };
            logger.debug("[TransformationUtils] Target tool parameter analysis", targetToolAnalysis);
            if (Object.keys(input).length === 0) {
                logger.error("[TransformationUtils] Critical: Target tool parameter extraction failed", {
                    toolName,
                    reason: "Both primary and nested extraction returned empty parameters",
                    impact: "AI response did not contain expected parameter structure",
                });
            }
        }
        // Final parameter extraction summary
        const finalExtractionSummary = {
            toolName,
            inputKeysCount: Object.keys(input).length,
            inputKeys: Object.keys(input),
            hasParameters: Object.keys(input).length > 0,
            duration: teRecord.duration ??
                teRecord.executionTime ??
                teRecord.responseTime ??
                0,
            hasOutput: !!(teRecord.output || teRecord.result || teRecord.response),
        };
        logger.debug("[TransformationUtils] Final parameter extraction result", finalExtractionSummary);
        // Enhanced output extraction with success indication
        const output = teRecord.output ||
            teRecord.result ||
            teRecord.response ||
            "success";
        // Enhanced duration extraction
        const duration = teRecord.duration ??
            teRecord.executionTime ??
            teRecord.responseTime ??
            0;
        return {
            name: toolName,
            input: input,
            output: output,
            duration: duration,
        };
    });
}
/**
 * Transform tool execution results from AI SDK format to internal format (for MCP generation)
 * Used in tryMCPGeneration method
 */
export function transformToolExecutionsForMCP(toolExecutions) {
    if (!toolExecutions || !Array.isArray(toolExecutions)) {
        return [];
    }
    return toolExecutions.map((te, index) => {
        const teRecord = te;
        // Enhanced tool name extraction matching the main function
        let toolName = teRecord.name ||
            teRecord.toolName ||
            teRecord.tool ||
            "";
        // Try nested toolCall extraction
        if (!toolName &&
            teRecord.toolCall &&
            typeof teRecord.toolCall === "object") {
            const toolCall = teRecord.toolCall;
            toolName =
                toolCall.name || toolCall.toolName || "";
        }
        // Fallback to avoid empty names
        if (!toolName) {
            toolName = `mcp_tool_execution_${index}`;
        }
        // Enhanced execution time extraction
        const executionTime = teRecord.duration ??
            teRecord.executionTime ??
            teRecord.responseTime ??
            0;
        // Enhanced success detection - check for actual success indicators
        let success = true; // Default to true
        // Check for explicit success/error indicators
        if (teRecord.success !== undefined) {
            success = Boolean(teRecord.success);
        }
        else if (teRecord.error !== undefined) {
            success = false;
        }
        else if (teRecord.status !== undefined) {
            const status = String(teRecord.status).toLowerCase().trim();
            success = !["error", "failed", "failure", "fail"].includes(status);
        }
        // Enhanced server ID extraction
        let serverId = teRecord.serverId ||
            teRecord.server ||
            teRecord.source ||
            undefined;
        // Try to extract from nested structures
        if (!serverId &&
            teRecord.toolCall &&
            typeof teRecord.toolCall === "object") {
            const toolCall = teRecord.toolCall;
            serverId =
                toolCall.serverId ||
                    toolCall.server ||
                    undefined;
        }
        return {
            toolName: toolName,
            executionTime: executionTime,
            success: success,
            serverId: serverId,
        };
    });
}
// ============================================================================
// AVAILABLE TOOLS TRANSFORMATIONS
// ============================================================================
/**
 * Transform available tools from internal format to GenerateResult format
 * Ensures consistent tool information structure across the API with schema normalization
 *
 * @param availableTools - Array of tool definitions from various sources (MCP servers, builtin tools, etc.)
 * @returns Array of normalized tool descriptions with consistent schema format
 *
 * @example
 * ```typescript
 * const tools = transformAvailableTools([
 *   { name: "calculator", description: "Math tool", server: "builtin", inputSchema: {...} }
 * ]);
 * // Returns: [{ name: "calculator", description: "Math tool", serverId: "builtin", schema: {...} }]
 * ```
 */
export function transformAvailableTools(availableTools) {
    if (!availableTools || !Array.isArray(availableTools)) {
        return [];
    }
    return availableTools.map((tool) => {
        const toolRecord = tool;
        let extractedParameters = {};
        const inputSchema = toolRecord.inputSchema;
        const directParameters = toolRecord.parameters;
        const fallbackSchema = toolRecord.schema;
        if (inputSchema && typeof inputSchema === "object") {
            // Use shared inlineJsonSchema for recursive $ref resolution
            const inlinedSchema = inlineJsonSchema(inputSchema);
            if (inlinedSchema.properties) {
                extractedParameters = {
                    type: inlinedSchema.type || "object",
                    properties: inlinedSchema.properties,
                    required: inlinedSchema.required || [],
                    ...inlinedSchema,
                };
            }
            else if (inlinedSchema.type === "object") {
                extractedParameters = inlinedSchema;
            }
            else {
                extractedParameters = inlinedSchema;
            }
        }
        else if (directParameters && typeof directParameters === "object") {
            // Also inline $ref for direct parameters if present
            extractedParameters = inlineJsonSchema(directParameters);
        }
        else if (fallbackSchema && typeof fallbackSchema === "object") {
            // Also inline $ref for fallback schema if present
            extractedParameters = inlineJsonSchema(fallbackSchema);
        }
        if (!extractedParameters || typeof extractedParameters !== "object") {
            extractedParameters = {};
        }
        if (extractedParameters &&
            !extractedParameters.type &&
            extractedParameters.properties) {
            extractedParameters.type = "object";
        }
        return {
            name: tool.name || "",
            description: tool.description || "",
            server: tool.server || "",
            parameters: extractedParameters,
        };
    });
}
/**
 * Transform tools for MCP generation format
 * Simple transformation for internal MCP tool lists
 */
export function transformToolsForMCP(availableTools) {
    return availableTools.map((tool) => ({
        name: tool.name,
        description: tool.description,
        server: tool.server,
        category: tool.category,
    }));
}
/**
 * Transform tools to expected format with required properties
 * Used in getAllAvailableTools method for final output
 */
export function transformToolsToExpectedFormat(tools) {
    return tools.map((tool) => ({
        name: tool.name,
        description: tool.description || "No description available",
        server: tool.serverId || "unknown",
        category: tool.category,
        inputSchema: tool.inputSchema,
    }));
}
// ============================================================================
// STRING AND ARRAY TRANSFORMATIONS
// ============================================================================
/**
 * Extract tool names from tool objects
 * Common pattern for creating arrays of tool names
 */
export function extractToolNames(tools) {
    return tools.map((tool) => tool.name);
}
/**
 * Extract object keys as a comma-separated string
 * Common pattern for logging and debugging
 */
export function getKeysAsString(obj, fallback = "none") {
    const keys = Object.keys(obj);
    return keys.length > 0 ? keys.join(", ") : fallback;
}
/**
 * Count object properties
 * Common pattern for metrics and logging
 */
export function getKeyCount(obj) {
    return Object.keys(obj).length;
}
// ============================================================================
// SCHEMA TRANSFORMATIONS
// ============================================================================
/**
 * Transform schema properties to parameter descriptions
 * Used in tool-aware system prompt generation
 */
export function transformSchemaToParameterDescription(schema) {
    if (!schema?.properties) {
        return "";
    }
    const requiredParams = new Set(schema.required || []);
    return Object.entries(schema.properties)
        .map(([key, value]) => {
        const typedValue = value;
        const required = requiredParams.has(key) ? " (required)" : "";
        const description = typedValue.description
            ? ` - ${typedValue.description}`
            : "";
        return `  - ${key}: ${typedValue.type || "unknown"}${required}${description}`;
    })
        .join("\n");
}
/**
 * Transform tools to tool descriptions for system prompts
 * Consolidated pattern for creating tool-aware prompts
 */
export function transformToolsToDescriptions(availableTools) {
    return availableTools
        .map((tool) => {
        const schema = tool.inputSchema;
        let params = "";
        if (schema?.properties) {
            params = transformSchemaToParameterDescription(schema);
        }
        return `- ${tool.name}: ${tool.description} (from ${tool.server})\n${params}`;
    })
        .join("\n\n");
}
// ============================================================================
// VALIDATION TRANSFORMATIONS
// ============================================================================
/**
 * Transform parameters for validation
 * Common pattern when logging or checking parameter structures
 */
export function transformParamsForLogging(params) {
    if (!params || typeof params !== "object") {
        return String(params);
    }
    const record = params;
    return `${Object.keys(record).length} params`;
}
/**
 * Safe property extraction from unknown objects
 * Common pattern for safely accessing properties from unknown structures
 */
export function safeExtractProperty(obj, key, fallback) {
    if (!obj || typeof obj !== "object" || obj === null) {
        return fallback;
    }
    const record = obj;
    const value = record[key];
    return value !== undefined ? value : fallback;
}
/**
 * Safe extraction of string properties
 * Specialized version for string properties with fallback
 */
export function safeExtractString(obj, key, fallback = "") {
    const value = safeExtractProperty(obj, key, fallback);
    return typeof value === "string" ? value : fallback;
}
/**
 * Safe extraction of number properties
 * Specialized version for number properties with fallback
 */
export function safeExtractNumber(obj, key, fallback = 0) {
    const value = safeExtractProperty(obj, key, fallback);
    return typeof value === "number" ? value : fallback;
}
/**
 * Safe extraction of boolean properties
 * Specialized version for boolean properties with fallback
 */
export function safeExtractBoolean(obj, key, fallback = false) {
    const value = safeExtractProperty(obj, key, fallback);
    return typeof value === "boolean" ? value : fallback;
}
// ============================================================================
// COLLECTION TRANSFORMATIONS
// ============================================================================
/**
 * Transform Map to array of values
 * Common pattern for converting tool maps to arrays
 */
export function mapToArray(map) {
    return Array.from(map.values());
}
/**
 * Transform Map to array of key-value pairs
 * Common pattern for processing map entries
 */
export function mapToEntries(map) {
    return Array.from(map.entries());
}
/**
 * Group array items by a key
 * Common pattern for organizing tools or other objects by category
 */
export function groupBy(items, keyFn) {
    const groups = new Map();
    for (const item of items) {
        const key = keyFn(item);
        const existing = groups.get(key) || [];
        existing.push(item);
        groups.set(key, existing);
    }
    return groups;
}
/**
 * Remove undefined properties from objects
 * Common pattern for cleaning up object structures
 */
export function removeUndefinedProperties(obj) {
    const cleaned = {};
    for (const [key, value] of Object.entries(obj)) {
        if (value !== undefined) {
            cleaned[key] = value;
        }
    }
    return cleaned;
}
/**
 * Merge objects with undefined handling
 * Common pattern for combining configuration objects
 */
export function mergeWithUndefinedHandling(target, ...sources) {
    const result = { ...target };
    for (const source of sources) {
        for (const [key, value] of Object.entries(source)) {
            if (value !== undefined) {
                result[key] = value;
            }
        }
    }
    return result;
}
// ============================================================================
// TOOL OPTIMIZATION UTILITIES
// ============================================================================
/**
 * Optimize tool information for collection with minimal object creation
 * Consolidates repeated optimization patterns across different tool sources
 *
 * @param tool - Tool information to optimize
 * @param defaults - Default values to apply if missing
 * @returns Optimized tool with minimal object creation
 *
 * @example
 * ```typescript
 * const optimized = optimizeToolForCollection(tool, {
 *   serverId: "builtin",
 *   category: "math"
 * });
 * ```
 */
export function optimizeToolForCollection(tool, defaults) {
    // Check what properties actually need modification
    const needsDescription = !tool.description && defaults.description;
    const needsServerId = !tool.serverId && defaults.serverId;
    const needsCategory = !tool.category && defaults.category;
    const needsInputSchema = !tool.inputSchema && defaults.inputSchema;
    const hasParametersConflict = tool.inputSchema && "parameters" in tool;
    // Only create new object if modifications are actually needed
    if (!needsDescription &&
        !needsServerId &&
        !needsCategory &&
        !needsInputSchema &&
        !hasParametersConflict) {
        return tool; // Return original tool without modification
    }
    // Create optimized tool with only necessary changes
    const optimizedTool = {
        ...tool,
        ...(needsDescription && { description: defaults.description }),
        ...(needsServerId && { serverId: defaults.serverId }),
        ...(needsCategory && { category: defaults.category }),
        ...(needsInputSchema && { inputSchema: defaults.inputSchema }),
    };
    // Clean up schema conflicts if present
    if (hasParametersConflict) {
        const cleanedTool = { ...optimizedTool };
        delete cleanedTool.parameters;
        return cleanedTool;
    }
    return optimizedTool;
}
//# sourceMappingURL=transformationUtils.js.map