import { z } from "zod";
import { lookupCommand, getAllCommands } from "../../commands/commandLibrary.js";
import { logger } from "../../utils/logger.js";
import { AnalyticsService } from "../../services/AnalyticsService.js";
const TOOL_NAME = "skyramp_one_click_tool";
/**
 * Generates the `workflow` parameter description from the live command library.
 * The LLM reads this when filling the tool call, matches the user's intent against
 * the trigger phrases / variant phrases / context indicators, and supplies the
 * matching workflow ID. No hardcoded enum — adding a new workflow to the library
 * automatically updates this description.
 */
function buildWorkflowParamDescription() {
    const commands = getAllCommands();
    const sections = commands.map((cmd) => {
        const indicators = cmd.intent.contextIndicators
            .map((c) => `  - ${c}`)
            .join("\n");
        const exampleBlock = cmd.intent.examples
            ? `\n  Examples (USE):\n${cmd.intent.examples.use.map((e) => `    - "${e}" → ${cmd.id}`).join("\n")}` +
                `\n  Examples (DO NOT USE):\n${cmd.intent.examples.doNotUse.map((e) => `    - "${e}"`).join("\n")}`
            : "";
        return (`- ID: "${cmd.id}"\n` +
            `  Purpose: ${cmd.intent.purpose}\n` +
            `  Workflow: ${cmd.intent.workflowSummary}\n` +
            `  When to use (and when not to):\n${indicators}` +
            exampleBlock);
    });
    return (`The workflow to execute. Match the user's intent against the available workflows below and pass the matching workflow ID.\n\n` +
        `Available workflows:\n${sections.join("\n\n")}`);
}
const oneClickSchema = z.object({
    workflow: z.string().describe(buildWorkflowParamDescription()),
    repositoryPath: z
        .string()
        .describe("Absolute path to the repository (e.g., /Users/dev/my-repo). Required for all commands."),
    endpointURL: z
        .string()
        .optional()
        .describe("Full URL of the endpoint to test. Used by test_given_endpoint_comprehensively and full_repo_scan_recommend_generate_and_execute_top_n_tests. If omitted, use api.baseUrl + path from workspace or recommendation."),
    apiSchema: z
        .string()
        .optional()
        .describe("Path or URL to OpenAPI/Swagger schema. If omitted, use schema from workspace or analysis."),
    topN: z
        .number()
        .optional()
        .describe("Number of top recommended test types to generate (e.g. 3–5). Default is 3. Used by full_repo_scan_recommend_generate_and_execute_top_n_tests."),
    token: z
        .string()
        .optional()
        .describe("Authentication/session token for test execution. Always pass this to skyramp_execute_test to avoid auth errors; use empty string '' if no auth required."),
});
/**
 * Build workflow instruction text from any command definition and params.
 */
function buildWorkflowFromCommand(cmd, params) {
    const getParamDisplay = (key) => {
        const v = params[key];
        if (v === undefined || v === null)
            return `(from user or default)`;
        const lowerKey = key.toLowerCase();
        const isSensitive = lowerKey === "token" ||
            lowerKey.includes("token") ||
            lowerKey.includes("secret") ||
            lowerKey.includes("password");
        if (isSensitive)
            return `(provided)`;
        return String(v);
    };
    const stepLines = [];
    for (const step of cmd.steps) {
        let block = `## Step ${step.stepIndex}: ${step.title}\n\n${step.description}`;
        if (step.toolCall) {
            const tc = step.toolCall;
            const inputLines = [];
            for (const [name, spec] of Object.entries(tc.inputs)) {
                if (spec.source === "user") {
                    inputLines.push(`- \`${name}\`: \`${getParamDisplay(spec.paramKey)}\` (user param ${spec.paramKey})`);
                }
                else if (spec.source === "step") {
                    inputLines.push(`- \`${name}\`: **from Step ${spec.stepIndex} output** \`${spec.outputKey}\` (use the value produced by that step)`);
                }
                else {
                    inputLines.push(`- \`${name}\`: \`${spec.value}\``);
                }
            }
            block += `\n\n**Call \`${tc.toolName}\`** with:\n${inputLines.join("\n")}`;
            if (tc.outputs?.length) {
                block += `\n\nCapture for later steps: ${tc.outputs.join(", ")}.`;
            }
        }
        if (step.conditionalGuidance) {
            block += `\n\n**Note**: ${step.conditionalGuidance}`;
        }
        stepLines.push(block);
    }
    const intro = `# One-Click Workflow: ${cmd.name}

${cmd.description}

Execute the following steps in order. Pass outputs (e.g. state file path) from one step as inputs to the next. Do not skip steps.

**State files**: Do **not** create any state files in the user repository. Use only state files created by \`skyramp_analyze_changes\` (it writes to system temp, e.g. \`/tmp\`). Use the state file path returned in that tool's response; never create or write state files inside the repo.

**Repository**: \`${params.repositoryPath}\`
---

`;
    return (intro +
        stepLines.join("\n\n---\n\n") +
        `

---

## Progress and failures

- Execute steps in order. If a step fails, report the error and suggest recovery.
- When calling \`skyramp_execute_test\`, always pass the \`token\` parameter (session token).
- **UI and E2E tests**: If the workflow includes generating UI or E2E tests, you must run \`skyramp_start_trace_collection\` (with playwright enabled and an absolute outputDir) before generating, then \`skyramp_stop_trace_collection\` (playwrightEnabled: true) after the user has interacted with the app. Use the produced trace file and Playwright zip as \`playwrightInput\` (and \`trace\` for E2E) when calling the UI or E2E test generation tools.
- **This tool is currently in Early Preview stage. Please verify the results.**
`);
}
export function registerOneClickTool(server) {
    server.registerTool(TOOL_NAME, {
        description: `Execute predefined, multi-step testing workflows with a single tool call.

**Purpose**: The One-Click Commands tool provides a mechanism to define and execute complex, multi-step testing workflows by orchestrating multiple MCP tools in sequence. Commands enable users to accomplish high-level testing goals (e.g., "comprehensively test this endpoint") through a single invocation, without requiring new MCP tool implementations for each workflow.

**When to use**:
- When the user names a specific endpoint and explicitly asks for comprehensive, thorough, or deep testing (e.g. "comprehensively test this endpoint", "thoroughly test the products endpoint"): MUST call this tool with workflow \`test_given_endpoint_comprehensively\`. Do NOT self-orchestrate — call this tool first and follow the returned instructions.
- When the user wants to scan the entire repo (no specific endpoint, no PR diff) to get ranked recommendations, generate top N types, and execute: MUST call this tool with workflow \`full_repo_scan_recommend_generate_and_execute_top_n_tests\`.
- Do NOT invoke these workflows for simple single-tool requests such as "generate a smoke test" or "run this test" — call the relevant tool directly instead.

**How it works**: Pass the \`workflow\` ID that matches the user's intent (see the \`workflow\` parameter description for available workflows and their trigger phrases). The tool returns a **workflow specification** (step-by-step instructions). You must then **execute that workflow** by calling the listed MCP tools in order, passing outputs (e.g. state file paths) from one step as inputs to the next. The tool does not execute other tools itself; it provides the declarative workflow for you to run.

**Design**:
- **MCP-only**: Workflows orchestrate only MCP tools; no CLI execution.
- **Declarative**: Workflows are sequences of tool calls with dependencies.
- **State-efficient**: State files are created only by recommendation/map tools (in system temp, e.g. /tmp); do not create any state files in the user repository.
- **Composable**: Complex workflows are built from existing Skyramp tools.`,
        inputSchema: oneClickSchema.shape,
    }, async (params) => {
        let errorResult;
        try {
            logger.info("One-click tool invoked", {
                workflow: params.workflow,
                repositoryPath: params.repositoryPath,
            });
            const cmd = lookupCommand(params.workflow);
            const oneClickParams = {
                workflow: params.workflow,
                repositoryPath: params.repositoryPath,
                endpointURL: params.endpointURL,
                apiSchema: params.apiSchema,
                topN: params.topN ?? 3,
                token: params.token ?? "",
            };
            const workflowText = buildWorkflowFromCommand(cmd, oneClickParams);
            return {
                content: [
                    {
                        type: "text",
                        text: workflowText,
                    },
                ],
                isError: false,
            };
        }
        catch (error) {
            const errorMessage = error instanceof Error ? error.message : String(error);
            logger.error("One-click tool failed", { error: errorMessage });
            errorResult = {
                content: [
                    {
                        type: "text",
                        text: `Error running one-click command: ${errorMessage}`,
                    },
                ],
                isError: true,
            };
            return errorResult;
        }
        finally {
            AnalyticsService.pushMCPToolEvent(TOOL_NAME, errorResult, {
                workflow: params.workflow,
            });
        }
    });
}
