/**
 * ============================================================
 *  src/tools/webbrowser.ts —— WebBrowser 工具
 * ------------------------------------------------------------
 *  用 Playwright 控制 headless 浏览器：导航、截图、内容提取、表单交互。
 *
 *  依赖：playwright-core（需要额外安装浏览器：npx playwright install chromium）
 *
 *  输入：
 *    action    必填，'navigate'|'screenshot'|'getContent'|'click'|'fill'|'submit'
 *    url       可选，navigate 时必需
 *    selector  可选，click/fill/submit 时必需
 *    value     可选，fill 时必需
 *    timeout   可选，默认 30000ms
 *
 *  输出：
 *    { ok: true, content: string } | { ok: false, error: string }
 * ============================================================
 */
import { z } from 'zod';
import { DEFAULT_MAX_RESULT_SIZE_CHARS } from '../types.js';
import { toToolParameters } from '../../utils/zodToJson.js';
import { getBrowserPage, screenshotPath } from './browser.js';
// ---------------- 1. Zod 输入 schema ----------------
const inputSchema = z.object({
    action: z
        .enum(['navigate', 'screenshot', 'getContent', 'click', 'fill', 'submit'])
        .describe('Browser action to perform'),
    url: z
        .string()
        .url()
        .optional()
        .describe('URL to navigate to (required for navigate action)'),
    selector: z
        .string()
        .optional()
        .describe('CSS selector for click/fill/submit actions'),
    value: z.string().optional().describe('Value to fill in input fields'),
    timeout: z
        .number()
        .int()
        .positive()
        .optional()
        .describe('Timeout in milliseconds (default: 30000)'),
});
// ---------------- 2. JSON Schema（由 Zod 自动派生） ----------------
const parameters = toToolParameters(inputSchema);
// ---------------- 3. Description ----------------
const description = `Control a headless web browser. Navigate to URLs, take screenshots, and interact with web pages.

When to use WebBrowser vs WebSearch:
- WebSearch: When you need to find information or discover URLs through search
- WebBrowser: When you need to interact with a specific web page (navigate, click, fill forms, get content, take screenshots)

Input parameters:
  - action (required): The browser action. One of:
    - navigate: Go to a URL (requires url parameter)
    - screenshot: Take a screenshot of the current page
    - getContent: Extract text content from the current page
    - click: Click an element (requires selector parameter)
    - fill: Fill an input field (requires selector and value parameters)
    - submit: Submit a form (requires selector parameter)
  - url (optional): URL to navigate to (required for navigate action, must be a valid URL)
  - selector (optional): CSS selector for click/fill/submit actions
  - value (optional): Value to fill in input fields
  - timeout (optional): Timeout in milliseconds for actions (default: 30000)

Usage notes:
  - The browser runs headless (no visible window)
  - Screenshots are saved to temporary files (/tmp/browser-*.png)
  - Content is truncated to 50000 characters max
  - Only one browser instance is maintained per session
  - Requires: npm install playwright-core && npx playwright install chromium

Example actions:
  - Navigate and get content: { action: "navigate", url: "https://example.com" }
  - Take screenshot: { action: "screenshot" }
  - Click element: { action: "click", selector: "#submit-btn" }
  - Fill form field: { action: "fill", selector: "input[name='email']", value: "user@example.com" }`;
// ---------------- 4. call() 实现 ----------------
async function call(input, signal) {
    const { action, url, selector, value, timeout = 30000 } = input;
    let page;
    try {
        page = await getBrowserPage();
    }
    catch (e) {
        return {
            ok: false,
            error: `无法启动浏览器：${e instanceof Error ? e.message : String(e)}`,
        };
    }
    try {
        switch (action) {
            case 'navigate': {
                if (!url) {
                    return { ok: false, error: 'navigate action requires url parameter' };
                }
                await page.goto(url, { timeout, waitUntil: 'domcontentloaded' });
                const content = await page.evaluate(() => document.body.innerText);
                const screenshot = screenshotPath('browser-nav');
                await page.screenshot({ path: screenshot });
                const truncatedContent = content.substring(0, 50_000);
                return {
                    ok: true,
                    content: [
                        `[Navigate] ${page.url()}`,
                        `Screenshot: ${screenshot}`,
                        '',
                        '--- Page Content (first 50000 chars) ---',
                        truncatedContent,
                        content.length > 50_000 ? '\n... (truncated)' : '',
                    ].join('\n'),
                };
            }
            case 'screenshot': {
                const screenshot = screenshotPath('browser-screenshot');
                await page.screenshot({ path: screenshot });
                return {
                    ok: true,
                    content: `[Screenshot] ${page.url()}\nSaved: ${screenshot}`,
                };
            }
            case 'getContent': {
                const content = await page.evaluate(() => document.body.innerText);
                const truncated = content.substring(0, 50_000);
                return {
                    ok: true,
                    content: [
                        `[Page Content] ${page.url()}`,
                        '',
                        truncated,
                        content.length > 50_000 ? '\n... (truncated at 50000 chars)' : '',
                    ].join('\n'),
                };
            }
            case 'click': {
                if (!selector) {
                    return { ok: false, error: 'click action requires selector parameter' };
                }
                await page.click(selector, { timeout });
                return {
                    ok: true,
                    content: `[Click] ${selector}\nCurrent URL: ${page.url()}`,
                };
            }
            case 'fill': {
                if (!selector || value === undefined) {
                    return { ok: false, error: 'fill action requires selector and value parameters' };
                }
                await page.fill(selector, value);
                return {
                    ok: true,
                    content: `[Fill] ${selector} = "${value}"\nCurrent URL: ${page.url()}`,
                };
            }
            case 'submit': {
                if (!selector) {
                    return { ok: false, error: 'submit action requires selector parameter' };
                }
                // Click and wait for navigation if it triggers one
                await Promise.all([
                    page.waitForNavigation({ timeout }).catch(() => { }),
                    page.click(selector, { timeout }),
                ]);
                return {
                    ok: true,
                    content: `[Submit] ${selector}\nCurrent URL: ${page.url()}`,
                };
            }
            default:
                return { ok: false, error: `Unknown action: ${action}` };
        }
    }
    catch (e) {
        const message = e instanceof Error ? e.message : String(e);
        // 截断超长错误信息
        const truncated = message.length > DEFAULT_MAX_RESULT_SIZE_CHARS
            ? message.substring(0, DEFAULT_MAX_RESULT_SIZE_CHARS) + '\n... (truncated)'
            : message;
        return { ok: false, error: `[${action}] Error: ${truncated}` };
    }
}
// ---------------- 5. 导出 ----------------
export const webbrowserTool = {
    name: 'WebBrowser',
    description,
    inputSchema,
    parameters,
    isReadOnly: false,
    isConcurrencySafe: false,
    maxResultSizeChars: DEFAULT_MAX_RESULT_SIZE_CHARS,
    call,
};
