/**
 * Bridge between judge system and Playwright MCP server.
 *
 * Provides a high-level interface for browser automation
 * through the MCP protocol.
 */
import { MCPClient } from "@superblocksteam/clark";
/**
 * Bridge to Playwright MCP server for browser automation.
 *
 * Provides a simplified interface for common browser
 * automation tasks used by the judge system.
 */
export class PlaywrightBridge {
    logger;
    mcpClient;
    constructor(serverUrl, logger) {
        this.logger = logger;
        this.mcpClient = new MCPClient(serverUrl, logger);
    }
    /**
     * Initializes the bridge connection.
     */
    async initialize() {
        await this.mcpClient.connect();
        this.logger.info("Playwright bridge initialized");
    }
    /**
     * Navigates to a URL.
     *
     * @param url - Target URL
     * @returns Navigation result
     */
    async navigate(url) {
        return this.executeAction("navigate", { url });
    }
    /**
     * Clicks an element.
     *
     * @param selector - Element selector
     * @returns Click result
     */
    async click(selector) {
        return this.executeAction("click", { selector });
    }
    /**
     * Fills an input field.
     *
     * @param selector - Input selector
     * @param value - Value to fill
     * @returns Fill result
     */
    async fill(selector, value) {
        return this.executeAction("fill", { selector, value });
    }
    /**
     * Captures a screenshot.
     *
     * @param fullPage - Whether to capture full page
     * @returns Screenshot result with base64 data
     */
    async screenshot(fullPage = false) {
        return this.executeAction("screenshot", { fullPage });
    }
    /**
     * Gets text content from an element.
     *
     * @param selector - Element selector
     * @returns Text content
     */
    async getText(selector) {
        return this.executeAction("getText", { selector });
    }
    /**
     * Waits for a selector to appear.
     *
     * @param selector - Element selector
     * @param timeout - Wait timeout in milliseconds
     * @returns Wait result
     */
    async waitForSelector(selector, timeout = 30000) {
        return this.executeAction("waitForSelector", { selector, timeout });
    }
    /**
     * Evaluates JavaScript in the page context.
     *
     * @param script - JavaScript to execute
     * @returns Evaluation result
     */
    async evaluate(script) {
        this.logger.info(`Evaluate called - length: ${script.length}, preview: ${script.substring(0, 100)}`);
        // Validate script doesn't contain module syntax
        if (script.includes("import ") ||
            script.includes("export ") ||
            script.includes("require(")) {
            this.logger.warn("Script contains module syntax", `Script preview: ${script.substring(0, 200)}`);
            // Return error to the model instead of throwing
            return {
                success: false,
                error: "Cannot use import/export/require statements in browser evaluate context. Use plain JavaScript only. For example, use 'document.querySelector' instead of importing libraries.",
            };
        }
        this.logger.info("Script validation passed, executing action");
        return this.executeAction("evaluate", { script });
    }
    /**
     * Gets the current page URL.
     *
     * @returns Current URL
     */
    async getUrl() {
        return this.executeAction("getUrl", {});
    }
    /**
     * Reloads the current page.
     *
     * @returns Reload result
     */
    async reload() {
        return this.executeAction("reload", {});
    }
    /**
     * Executes a generic Playwright action.
     *
     * @param action - Action name
     * @param params - Action parameters
     * @returns Action result
     */
    async executeAction(action, params) {
        this.logger.info(`Executing action: ${action}, params: ${Object.keys(params).join(", ")}`);
        try {
            const toolArgs = { action, ...params };
            const result = await this.mcpClient.callTool("playwright_action", toolArgs);
            this.logger.info(`Action succeeded: ${action}`);
            return { success: true, data: result };
        }
        catch (error) {
            this.logger.error(`Action ${action} failed: ${String(error)}`);
            return { success: false, error: String(error) };
        }
    }
    /**
     * Executes multiple actions in sequence.
     *
     * @param actions - Array of actions to execute
     * @returns Results of all actions
     */
    async executeSequence(actions) {
        const results = [];
        for (const action of actions) {
            let result;
            if (action.navigate) {
                result = await this.navigate(action.navigate.url);
            }
            else if (action.click) {
                result = await this.click(action.click.selector);
            }
            else if (action.fill) {
                result = await this.fill(action.fill.selector, action.fill.value);
            }
            else if (action.screenshot) {
                result = await this.screenshot(action.screenshot.fullPage);
            }
            else if (action.getText) {
                result = await this.getText(action.getText.selector);
            }
            else if (action.waitForSelector) {
                result = await this.waitForSelector(action.waitForSelector.selector, action.waitForSelector.timeout);
            }
            else if (action.evaluate) {
                result = await this.evaluate(action.evaluate.script);
            }
            else if (action.getUrl) {
                result = await this.getUrl();
            }
            else if (action.reload) {
                result = await this.reload();
            }
            else {
                result = {
                    success: false,
                    error: "Unknown action type",
                };
            }
            results.push(result);
            // Stop sequence on failure
            if (!result.success) {
                break;
            }
        }
        return results;
    }
    /**
     * Cleans up the bridge connection.
     */
    async cleanup() {
        await this.mcpClient.disconnect();
        this.logger.info("Playwright bridge cleaned up");
    }
    /**
     * Checks if the bridge is connected.
     *
     * @returns True if connected
     */
    isConnected() {
        return this.mcpClient.isConnected();
    }
}
//# sourceMappingURL=playwright-bridge.js.map