// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import { assert } from '//resources/js/assert.js';
import { formatPageVisitHistory, formatTranscript } from '../persona.js';
import { ScrollGranularity } from '../tools.mojom-webui.js';
import { kBuiltInToolDefinitions } from './../generated_tool_definitions.js';
export class ToolExecutor {
    toolsRemote;
    pageContextManager;
    journal;
    personaName;
    constructor(toolsRemote, pageContextManager, journal, personaName) {
        this.toolsRemote = toolsRemote;
        this.pageContextManager = pageContextManager;
        this.journal = journal;
        this.personaName = personaName;
    }
    getToolDefinitions() {
        const tools = JSON.parse(kBuiltInToolDefinitions);
        assert(tools.length > 0 && tools[0].functionDeclarations);
        tools[0].functionDeclarations.push({
            name: 'get_page_content',
            description: 'Use `get_page_content` if you need the ' +
                'full text of the current page.',
        }, {
            name: 'get_session_history',
            description: 'Use `get_session_history` to recall ' +
                'details from earlier in the session.',
        });
        return JSON.stringify(tools);
    }
    async executeTool(name, args) {
        try {
            const outResult = { success: true, scheduling: 'SILENT' };
            const call = { name, args };
            switch (call.name) {
                case 'open_url': {
                    await this.toolsRemote.openUrl(call.args.url, call.args.new_tab);
                    break;
                }
                case 'follow_link': {
                    await this.toolsRemote.followLink(call.args.id);
                    break;
                }
                case 'perform_search': {
                    await this.toolsRemote.performSearch(call.args.query, call.args.new_tab);
                    break;
                }
                case 'switch_tab': {
                    // Mojo result<T, string> bindings resolve to T on success and reject
                    // with string on error.
                    const switchTabResult = await this.toolsRemote.switchTab(call.args.query);
                    Object.assign(outResult, switchTabResult);
                    break;
                }
                case 'close_current_tab':
                    await this.toolsRemote.closeCurrentTab();
                    break;
                case 'go_back':
                    await this.toolsRemote.goBack();
                    break;
                case 'go_forward':
                    await this.toolsRemote.goForward();
                    break;
                case 'reload_page':
                    await this.toolsRemote.reloadPage();
                    break;
                case 'find_and_highlight': {
                    await this.toolsRemote.findAndHighlight(call.args.query);
                    break;
                }
                case 'scroll':
                    await this.execScroll(call.args);
                    break;
                case 'play_video':
                    await this.toolsRemote.playVideo();
                    break;
                case 'pause_video':
                    await this.toolsRemote.pauseVideo();
                    break;
                case 'seek_to_timestamp': {
                    await this.toolsRemote.seekToTimestamp(call.args.timecode);
                    break;
                }
                case 'translate_page': {
                    await this.toolsRemote.translatePage(call.args.target_language);
                    break;
                }
                case 'get_page_content': {
                    outResult['content'] = this.pageContextManager.pageContext?.content ||
                        'No content available for this page.';
                    break;
                }
                case 'get_session_history': {
                    const turns = this.journal.getTurnEntries();
                    const pages = this.journal.getPageVisitEntries();
                    const transcript = formatTranscript(turns, this.personaName);
                    const pageHistory = formatPageVisitHistory(pages);
                    outResult['history'] = `## Pages Visited\n${pageHistory}\n\n` +
                        `## Conversation History\n${transcript}`;
                    break;
                }
                case 'invoke_glic': {
                    const glicResult = await this.toolsRemote.invokeGlic(call.args.prompt);
                    if (typeof glicResult === 'string') {
                        return { success: false, error: glicResult };
                    }
                    if (!glicResult || typeof glicResult !== 'object' ||
                        !('value' in glicResult)) {
                        return { success: false, error: 'Unknown result' };
                    }
                    outResult['response'] = glicResult.value;
                    outResult['scheduling'] = 'INTERRUPT';
                    break;
                }
                default:
                    return { success: false, error: `Unknown tool: ${name}` };
            }
            return outResult;
        }
        catch (e) {
            console.error(`Error executing tool ${name}:`, e);
            return { success: false, error: String(e) };
        }
    }
    async execScroll(args) {
        // TODO(b/513218774): Ideally generated_tool_definitions would also
        // generate a validator function for each tool to validate the incoming
        // Args objects so we could do this automatically for each tool.
        if (typeof args !== 'object' || typeof args.magnitude !== 'number' ||
            (args.granularity !== 'document' && args.granularity !== 'page')) {
            throw new Error(`Bad Scroll Args: ${JSON.stringify(args)}`);
        }
        const granularity = args.granularity === 'document' ?
            ScrollGranularity.kDocument :
            ScrollGranularity.kPage;
        await this.toolsRemote.scroll(granularity, args.magnitude);
    }
}
