import { deepCloneWith, isIterableObject } from '@takeshape/util';
import isEmpty from 'lodash/isEmpty.js';
import mapValues from 'lodash/mapValues.js';
import { parsePropertyRef } from "../../refs.js";
function migrateTool(tool, makePublic = false) {
    if (typeof tool === 'string') {
        return {
            name: parsePropertyRef(tool)?.propertyName ?? tool,
            execution: {
                type: 'graphql',
                query: {
                    ref: tool
                }
            }
        };
    }
    const name = 'name' in tool ? tool.name : (parsePropertyRef(tool.ref)?.propertyName ?? tool.ref);
    const description = 'description' in tool ? tool.description : undefined;
    const { ref, selectionSet } = tool;
    let args;
    if ('args' in tool) {
        args = tool.args?.map((arg) => arg.argName);
    }
    const toolJson = {
        name,
        description,
        execution: {
            type: 'graphql',
            query: {
                ref,
                selectionSet,
                args
            }
        }
    };
    if (makePublic) {
        toolJson.visibility = 'public';
    }
    return toolJson;
}
function migrateArgBindings(tool) {
    if (typeof tool === 'object' && 'args' in tool) {
        return tool.args?.filter((arg) => arg.type === 'variable');
    }
}
function makePublic(tool) {
    return { ...tool, visibility: 'public' };
}
function migrateAgent(migrateToolConfig, agent) {
    return {
        ...agent,
        historyStrategies: mapValues(agent.historyStrategies, (strat) => {
            if (strat.transform.type !== 'generate' || !strat.transform.tools?.length) {
                return strat;
            }
            return {
                ...strat,
                transform: {
                    ...strat.transform,
                    tools: strat.transform.tools.map((tool) => migrateToolConfig(tool))
                }
            };
        }),
        states: mapValues(agent.states, (state) => {
            if (state.execution.type === 'graphql' || !state.execution.tools?.length) {
                return state;
            }
            return {
                ...state,
                execution: {
                    ...state.execution,
                    tools: state.execution.tools.map((tool) => migrateToolConfig(tool))
                }
            };
        })
    };
}
const migrate = async (context, projectSchema) => {
    const { mcp, agents, shapes, queries, mutations, ...rest } = projectSchema;
    const migratedTools = {};
    const duplicateTools = new Set();
    const migrateToolConfig = (legacyTool) => {
        const { name, ...tool } = migrateTool(legacyTool);
        if (migratedTools[name]) {
            duplicateTools.add(name);
        }
        migratedTools[name] = tool;
        return {
            tool: `Tool.${name}`,
            argBindings: migrateArgBindings(legacyTool)
        };
    };
    const shapesQueriesMutations = deepCloneWith({ shapes, queries, mutations }, (value, key, parent) => {
        // migrate ai resolver tools
        if (key === 'tools' &&
            Array.isArray(value) &&
            isIterableObject(parent) &&
            (parent.name === 'ai:generateText' || parent.name === 'ai:chat')) {
            const tools = value;
            return tools.map((tool) => migrateToolConfig(tool));
        }
    });
    const migrated = {
        ...rest,
        ...shapesQueriesMutations,
        schemaVersion: '3.60.0'
    };
    if (mcp?.tools) {
        for (const tool of Object.values(mcp.tools)) {
            migrateTool(tool, true);
        }
    }
    if (agents) {
        migrated.agents = mapValues(agents, (agent) => migrateAgent(migrateToolConfig, agent));
    }
    // Only re-order the schema if we migrated tools
    if (!isEmpty(migratedTools)) {
        if (duplicateTools.size > 0) {
            context.logger.warn(`Duplicate tools ${[...duplicateTools].map((name) => `"${name}"`).join(', ')} found in project "${projectSchema.projectId}"`);
        }
        migrated.tools = migratedTools;
        return migrated;
    }
    return {
        ...projectSchema,
        schemaVersion: '3.60.0'
    };
};
export default migrate;
