import { baseSchema, languageSchema, TestType, codeRefactoringSchema, baseTraceSchema, } from "../../types/TestTypes.js";
import { z } from "zod";
import { AnalyticsService } from "../../services/AnalyticsService.js";
import { TestGenerationService, } from "../../services/TestGenerationService.js";
import { normalizeLanguageParams, resolveParamAliases, } from "../../utils/normalizeParams.js";
import { getPersonaPrefix } from "../../prompts/personas.js";
import { isTestbotEnabled } from "../../utils/featureFlags.js";
const TOOL_NAME = "skyramp_ui_test_generation";
export class UITestService extends TestGenerationService {
    getTestType() {
        return TestType.UI;
    }
    buildGenerationOptions(params) {
        const options = this.buildBaseGenerationOptions(params);
        return {
            ...options,
            playwrightInput: params.playwrightInput,
        };
    }
    async handleApiAnalysis(params) {
        return null;
    }
    async generateTest(params) {
        // Pass modularizeCode: false to the base so it does not emit its own
        // modularization CRITICAL. UITestService owns the full post-gen sequence.
        const result = await super.generateTest({ ...params, modularizeCode: false });
        if (result.isError)
            return result;
        if (!params.enhanceAssertions && !params.modularizeCode)
            return result;
        const content = [...result.content];
        content.push({
            type: "text",
            text: this.buildUIPostGenInstructions(!!params.enhanceAssertions, !!params.modularizeCode),
        });
        return { ...result, content };
    }
    buildUIPostGenInstructions(enhanceAssertions, modularize) {
        const steps = [];
        if (enhanceAssertions) {
            steps.push(`### Step ${steps.length + 1} — Enhance UI assertions [REQUIRED]\nCall \`skyramp_enhance_assertions\` with \`testFile\` set to the absolute path of the generated test file, \`testType: "ui"\`, and \`enhanceType: "generation"\`. Apply every instruction returned to that file.`);
        }
        if (modularize) {
            steps.push(`### Step ${steps.length + 1} — Modularize [REQUIRED]\nCall \`skyramp_modularization\` with \`testFile\` set to the absolute path of the generated test file, \`language\`, \`testType: "ui"\`, and \`isTraceBased: true\`.`);
        }
        const heading = enhanceAssertions && modularize
            ? "Enhance UI assertions and modularize the generated test"
            : enhanceAssertions
                ? "Enhance UI assertions in the generated test"
                : "Modularize the generated test";
        return `### CRITICAL NEXT STEP — ${heading}\n\n${steps.join("\n\n")}`;
    }
}
const ADD_ASSERTIONS_DEFAULT = isTestbotEnabled();
// Only include the original params in the schema
const uiTestSchema = {
    ...languageSchema.shape,
    enhanceAssertions: z
        .boolean()
        .default(ADD_ASSERTIONS_DEFAULT)
        .describe("When true, calls skyramp_enhance_assertions after test generation to add richer response-body assertions. Disabled by default. Automatically enabled when running as testbot-feature. Do not override the default value of this parameter, unless the user explicitly asks to enable it."),
    playwrightInput: z
        .string()
        .describe("MUST be absolute path to the playwright trace zip file like /path/to/trace.zip. Capture using browser_* tools + skyramp_export_zip, or via manual trace collection with skyramp_start_trace_collection/skyramp_stop_trace_collection."),
    include: baseTraceSchema.shape.include
        .optional()
        .describe("Array of FQDN strings to only include from trace data when correlating frontend actions with backend calls"),
    exclude: baseTraceSchema.shape.exclude
        .optional()
        .describe("Array of FQDN strings to exclude from trace data when correlating frontend actions with backend calls"),
    output: baseSchema.shape.output,
    outputDir: baseSchema.shape.outputDir,
    force: baseSchema.shape.force,
    codeReuse: codeRefactoringSchema.shape.codeReuse,
    modularizeCode: codeRefactoringSchema.shape.modularizeCode.default(true),
};
export function registerUITestTool(server) {
    server.registerTool(TOOL_NAME, {
        description: `${getPersonaPrefix()}Before calling this tool, you MUST output a <thinking> block that covers:
1. The user-facing flow(s) captured in the Playwright trace (pages visited, actions taken)
2. Why a UI test (Playwright-based interaction replay) is the right choice for this intent
3. Which assertions this test should validate (page content, element state, navigation results)
4. The absolute path to the trace zip and the output directory, with source confirmation
If the trace zip path cannot be confirmed as an absolute path to an existing file, STOP and re-export before calling this tool.

---

Generate a UI test using Skyramp's deterministic test generation platform.

UI tests validate user interface functionality by simulating real user interactions with your web application. They test user workflows, form submissions, navigation, and ensure that your frontend works correctly across different browsers. UI tests use Playwright recordings as input to generate comprehensive test suites that replay user interactions, validate UI elements, and verify expected behaviors.

**Dynamic context (use this before recording):**
If \`skyramp_analyze_changes\` has already run and returned a \`sessionId\`, check the diff summary before deciding which flows to record:
\`skyramp://analysis/{sessionId}/diff\`
This tells you exactly which frontend files changed so you record traces for the right user flows — not just any page.

**Typical pipeline:** Use the \`browser_*\` tools (\`browser_navigate\`, \`browser_click\`, \`browser_type\`, etc.) to record user interactions, then call \`skyramp_export_zip\` to export a trace zip, then pass the absolute path to that zip as \`playwrightInput\` here.

**DOM Analyzer tools for blueprint-aware recording:** alongside the basic \`browser_*\` interaction tools, the Skyramp MCP exposes \`browser_blueprint\` (canonical PageBlueprint capture), \`browser_blueprint_diff\` (structured before/after delta), \`browser_widget_contract_lookup\` (interaction recipe for custom widgets by fingerprint), and the sitemap tools \`browser_sitemap_build\` / \`browser_sitemap_query\`. These enable semantic target selection and delta-derived assertions: capture a blueprint before each meaningful action, perform the action, then capture again — the diff between the two grounds your assertions in observable state changes rather than author guesses about what "success" looks like.

**CRITICAL: Do NOT use skyramp_start_trace_collection/skyramp_stop_trace_collection for UI test recording — use browser_* tools + skyramp_export_zip instead.**`,
        inputSchema: uiTestSchema,
        _meta: {
            keywords: ["ui test", "playwright"],
        },
    }, async (params) => {
        resolveParamAliases(params, {
            zipPath: "playwrightInput",
            tracePath: "playwrightInput",
            traceFile: "playwrightInput",
            zip: "playwrightInput",
        });
        normalizeLanguageParams(params);
        const service = new UITestService();
        const result = await service.generateTest(params);
        AnalyticsService.pushTestGenerationToolEvent(TOOL_NAME, result, params).catch(() => {
            // Silently ignore analytics errors
        });
        return result;
    });
}
