/*
 * Copyright (c) 2025 Bytedance, Inc. and its affiliates.
 * SPDX-License-Identifier: Apache-2.0
 */

import { getLogger } from '@tarko/agent';
import { AgentMode } from '../types';
import { getTimeString } from '../utils/hepler';
import { HOME_INSTRUCTION, PROXY_INSTRUCTION } from './code';

export const think_token = process.env.THINK_TOKEN || 'thinkt';
export const use_native_thinking = process.env.NATIVE_THINKING === 'true';
export const bypass_native_thinking = process.env.NATIVE_THINKING === 'bypass';

const logger = getLogger('prompt_t5');
const think_budget = '\n';

const task_description = `\nCurrent time is: ${getTimeString()}\n
As a professional personal assistant (Doubao) capable of solving various user problems, you will first reason through a user's problem to devise a solution, flexibly using a series of tools in combination with your thinking to accomplish the task and provide an accurate, reliable answer. While thinking and using tools, you may continuously and flexibly adjust your solution approach based on the results of tool calls. \n`;

const gui_task_description = `\nCurrent time is: ${getTimeString()}\n
You are a GUI agent. You are given a task and your action history, with screenshots. You need to perform the next action to complete the task. \n`;

const game_task_description = `You should begin by detailing the internal reasoning process, and then present the answer to the user. The reasoning process should be enclosed within <${think_token}> </${think_token}> tags, as follows:
<${think_token}> reasoning process here </${think_token}> answer here. 
You have different modes of thinking:
Unrestricted think mode: Engage in an internal thinking process with thorough reasoning and reflections. You have an unlimited budget for thinking tokens and can continue thinking until you fully solve the problem.
Efficient think mode: Provide a concise internal thinking process with efficient reasoning and reflections. You don't have a strict token budget but be less verbose and more direct in your thinking. 
No think mode: Respond directly to the question without any internal reasoning process or extra thinking tokens. Still follow the template with the minimum required thinking tokens to justify the answer. 
Budgeted think mode: Limit your internal reasoning and reflections to stay within the specified token budget
Based on the complexity of the problem, select the appropriate mode for reasoning among the provided options listed below.
Provided Mode(s):
Unrestricted think.
You are provided with a task description, a history of previous actions, and corresponding screenshots. Your goal is to perform the next action to complete the task. Please note that if performing the same action multiple times results in a static screen with no changes, you should attempt a modified or alternative action.`;

//Mixed scenarios use this additional_notes
const omni_additional_notes = `- Use english in your reasoning process. \n
${HOME_INSTRUCTION}
${PROXY_INSTRUCTION}
`;
//Pure GUI scenarios use this additional_notes_gui
const gui_additional_notes = `- You can execute multiple actions within a single tool call. For example:\n<seed:tool_call>\n<function=example_function_1>\n<parameter=example_parameter_1>value_1</parameter>\n<parameter=example_parameter_2>\nThis is the value for the second parameter\nthat can span\nmultiple lines\n</parameter>\n</function>\n\n<function=example_function_2>\n<parameter=example_parameter_3>value_4</parameter>\n</function>\n</seed:tool_call>`;

export const mcp_functions = `
{"type": "function", "name": "LinkReader", "description": "这是一个链接浏览工具，可以打开链接（可以是网页、pdf等）并根据需求描述汇总页面上的所有相关信息。建议对所有有价值的链接都调用该工具来获取信息，有价值的链接包括但不限于如下几种：1.任务中明确提供的网址，2.搜索结果提供的带有相关摘要的网址，3. 之前调用LinkReader返回的内容中包含的且判断可能含有有用信息的网址。请尽量避免自己凭空构造链接。", "parameters": {"properties": {"url": {"type": "string", "description": "目标链接，应该是一个完整的url（以 http 开头）"}, "description": {"type": "string", "description": "需求描述文本，详细描述在当前url内想要获取的内容"}}, "required": ["url", "description"]}}
{"type": "function", "name": "Search", "parameters": {"type": "object", "properties": {"query": {"type": "string", "description": "搜索问题"}}, "required": ["query"]}, "description": "这是一个联网搜索工具，输入搜索问题，返回网页列表与对应的摘要信息。搜索问题应该简洁清晰，复杂问题应该拆解成多步并一步一步搜索。如果没有搜索到有用的页面，可以调整问题描述（如减少限定词、更换搜索思路）后再次搜索。搜索结果质量和语种有关，对于中文资源可以尝试输入中文问题，非中资源可以尝试使用英文或对应语种。"}
`;
export const code_functions = `
{"type": "function", "name": "execute_bash", "description": "Execute a bash command in the terminal.\n* Long running commands: For commands that may run indefinitely, it should be run in the background and the output should be redirected to a file, e.g. command = \`python3 app.py > server.log 2>&1 &\`.\n* One command at a time: You can only execute one bash command at a time. If you need to run multiple commands sequentially, you can use \`&&\` or \`;\` to chain them together.\n", "parameters": {"type": "object", "properties": {"command": {"type": "string", "description": "The bash command to execute. Can be empty string to view additional logs when previous exit code is \`-1\`. Can be \`C-c\` (Ctrl+C) to interrupt the currently running process. Note: You can only execute one bash command at a time. If you need to run multiple commands sequentially, you can use \`&&\` or \`;\` to chain them together."}}, "required": ["command"]}}
{"type": "function", "name": "str_replace_editor", "description": "Custom editing tool for viewing, creating and editing files in plain-text format\n* State is persistent across command calls and discussions with the user\n* If \`path\` is a file, \`view\` displays the result of applying \`cat -n\`. If \`path\` is a directory, \`view\` lists non-hidden files and directories up to 2 levels deep\n* The \`create\` command cannot be used if the specified \`path\` already exists as a file\n* If a \`command\` generates a long output, it will be truncated and marked with \`<response clipped>\`\n* The \`undo_edit\` command will revert the last edit made to the file at \`path\`\n\nNotes for using the \`str_replace\` command:\n* The \`old_str\` parameter should match EXACTLY one or more consecutive lines from the original file. Be mindful of whitespaces!\n* If the \`old_str\` parameter is not unique in the file, the replacement will not be performed. Make sure to include enough context in \`old_str\` to make it unique\n* The \`new_str\` parameter should contain the edited lines that should replace the \`old_str\`\n", "parameters": {"type": "object", "properties": {"command": {"description": "The commands to run. Allowed options are: \`view\`, \`create\`, \`str_replace\`, \`insert\`, \`undo_edit\`.", "enum": ["view", "create", "str_replace", "insert", "undo_edit"], "type": "string"}, "path": {"description": "Absolute path to file or directory, e.g. \`/workspace/file.py\` or \`/workspace\`.", "type": "string"}, "file_text": {"description": "Required parameter of \`create\` command, with the content of the file to be created.", "type": "string"}, "old_str": {"description": "Required parameter of \`str_replace\` command containing the string in \`path\` to replace.", "type": "string"}, "new_str": {"description": "Optional parameter of \`str_replace\` command containing the new string (if not given, no string will be added). Required parameter of \`insert\` command containing the string to insert.", "type": "string"}, "insert_line": {"description": "Required parameter of \`insert\` command. The \`new_str\` will be inserted AFTER the line \`insert_line\` of \`path\`.", "type": "integer"}, "view_range": {"description": "Optional parameter of \`view\` command when \`path\` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting \`[start_line, -1]\` shows all lines from \`start_line\` to the end of the file.", "items": {"type": "integer"}, "type": "array"}}, "required": ["command", "path"]}}
{"type": "function", "name": "JupyterCI", "parameters": {"type": "object", "properties": {"code": {"type": "string", "description": "code"}, "timeout": {"type": "integer", "description": "timeout in seconds"}}, "required": ["code"]}, "description": " JupyterCI 一个保留状态的代码沙盒工具。你可以在此工具中运行python代码"}
`;
export const gui_functions = `
{"type": "function", "name": "navigate", "parameters": {"type": "object", "properties": {"content": {"type": "string", "description": "The url to navigate to."}}, "required": ["content"]}, "description": "Navigate to a url."}
{"type": "function", "name": "navigate_back", "parameters": {"type": "object", "properties": {}, "required": []}, "description": "Navigate back to the previous page."}
{"type": "function", "name": "click", "parameters": {"type": "object", "properties": {"point": {"type": "string", "description": "Click coordinates. The format is: <point>x y</point>"}}, "required": ["point"]}, "description": "Mouse left single click action."}
{"type": "function", "name": "drag", "parameters": {"type": "object", "properties": {"start_point": {"type": "string", "description": "Drag start point. The format is: <point>x y</point>"}, "end_point": {"type": "string", "description": "Drag end point. The format is: <point>x y</point>"}}, "required": ["start_point", "end_point"]}, "description": "Mouse left button drag action."}
{"type": "function", "name": "hotkey", "parameters": {"type": "object", "properties": {"key": {"type": "string", "description": "Hotkeys you want to press. Split keys with a space and use lowercase."}}, "required": ["key"]}, "description": "Press hotkey."}
{"type": "function", "name": "left_double", "parameters": {"type": "object", "properties": {"point": {"type": "string", "description": "Click coordinates. The format is: <point>x y</point>"}}, "required": ["point"]}, "description": "Mouse left double click action."}
{"type": "function", "name": "mouse_down", "parameters": {"type": "object", "properties": {"point": {"type": "string", "description": "Mouse down position. If not specified, default to execute on the current mouse position. The format is: <point>x y</point>"}, "button": {"type": "string", "description": "Down button. Default to left.", "enum": ["left", "right"]}}, "required": []}, "description": "Mouse down action."}
{"type": "function", "name": "mouse_up", "parameters": {"type": "object", "properties": {"point": {"type": "string", "description": "Mouse up position. If not specified, default to execute on the current mouse position. The format is: <point>x y</point>"}, "button": {"type": "string", "description": "Up button. Default to left.", "enum": ["left", "right"]}}, "required": []}, "description": "Mouse up action."}
{"type": "function", "name": "move_to", "parameters": {"type": "object", "properties": {"point": {"type": "string", "description": "Target coordinates. The format is: <point>x y</point>"}}, "required": ["point"]}, "description": "Mouse move action."}
{"type": "function", "name": "press", "parameters": {"type": "object", "properties": {"key": {"type": "string", "description": "Key you want to press. Only one key can be pressed at one time."}}, "required": ["key"]}, "description": "Press key."}
{"type": "function", "name": "release", "parameters": {"type": "object", "properties": {"key": {"type": "string", "description": "Key you want to release. Only one key can be released at one time."}}, "required": ["key"]}, "description": "Release key."}
{"type": "function", "name": "right_single", "parameters": {"type": "object", "properties": {"point": {"type": "string", "description": "Click coordinates. The format is: <point>x y</point>"}}, "required": ["point"]}, "description": "Mouse right single click action."}
{"type": "function", "name": "scroll", "parameters": {"type": "object", "properties": {"point": {"type": "string", "description": "Scroll start position. If not specified, default to execute on the current mouse position. The format is: <point>x y</point>"}, "direction": {"type": "string", "description": "Scroll direction.", "enum": ["up", "down", "left", "right"]}}, "required": ["direction"]}, "description": "Scroll action."}
{"type": "function", "name": "type", "parameters": {"type": "object", "properties": {"content": {"type": "string", "description": "Type content. If you want to submit your input, use \n at the end of content."}}, "required": ["content"]}, "description": "Type content."}
{"type": "function", "name": "wait", "parameters": {"type": "object", "properties": {"time": {"type": "integer", "description": "Wait time in seconds."}}, "required": []}, "description": "Wait for a while."}
`;

export const game_functions = `
{"type": "function", "name": "click", "parameters": {"type": "object", "properties": {"point": {"type": "string", "description": "Click coordinates. The format is: <point>x y</point>"}}, "required": ["point"]}, "description": "Mouse left single click action."}
{"type": "function", "name": "drag", "parameters": {"type": "object", "properties": {"start_point": {"type": "string", "description": "Drag start point. The format is: <point>x y</point>"}, "end_point": {"type": "string", "description": "Drag end point. The format is: <point>x y</point>"}}, "required": ["start_point", "end_point"]}, "description": "Mouse left button drag action."}
{"type": "function", "name": "hotkey", "parameters": {"type": "object", "properties": {"key": {"type": "string", "description": "Hotkeys you want to press. Split keys with a space and use lowercase."}}, "required": ["key"]}, "description": "Press hotkey."}
{"type": "function", "name": "left_double", "parameters": {"type": "object", "properties": {"point": {"type": "string", "description": "Click coordinates. The format is: <point>x y</point>"}}, "required": ["point"]}, "description": "Mouse left double click action."}
{"type": "function", "name": "mouse_down", "parameters": {"type": "object", "properties": {"point": {"type": "string", "description": "Mouse down position. If not specified, default to execute on the current mouse position. The format is: <point>x y</point>"}, "button": {"type": "string", "description": "Down button. Default to left.", "enum": ["left", "right"]}}, "required": []}, "description": "Mouse down action."}
{"type": "function", "name": "mouse_up", "parameters": {"type": "object", "properties": {"point": {"type": "string", "description": "Mouse up position. If not specified, default to execute on the current mouse position. The format is: <point>x y</point>"}, "button": {"type": "string", "description": "Up button. Default to left.", "enum": ["left", "right"]}}, "required": []}, "description": "Mouse up action."}
{"type": "function", "name": "move_to", "parameters": {"type": "object", "properties": {"point": {"type": "string", "description": "Target coordinates. The format is: <point>x y</point>"}}, "required": ["point"]}, "description": "Mouse move action."}
{"type": "function", "name": "press", "parameters": {"type": "object", "properties": {"key": {"type": "string", "description": "Key you want to press. Only one key can be pressed at one time."}}, "required": ["key"]}, "description": "Press key."}
{"type": "function", "name": "release", "parameters": {"type": "object", "properties": {"key": {"type": "string", "description": "Key you want to release. Only one key can be released at one time."}}, "required": ["key"]}, "description": "Release key."}
{"type": "function", "name": "right_single", "parameters": {"type": "object", "properties": {"point": {"type": "string", "description": "Click coordinates. The format is: <point>x y</point>"}}, "required": ["point"]}, "description": "Mouse right single click action."}
{"type": "function", "name": "scroll", "parameters": {"type": "object", "properties": {"point": {"type": "string", "description": "Scroll start position. If not specified, default to execute on the current mouse position. The format is: <point>x y</point>"}, "direction": {"type": "string", "description": "Scroll direction.", "enum": ["up", "down", "left", "right"]}}, "required": ["direction"]}, "description": "Scroll action."}
{"type": "function", "name": "type", "parameters": {"type": "object", "properties": {"content": {"type": "string", "description": "Type content. If you want to submit your input, use \n at the end of content."}}, "required": ["content"]}, "description": "Type content."}
{"type": "function", "name": "wait", "parameters": {"type": "object", "properties": {"time": {"type": "integer", "description": "Wait time in seconds."}}, "required": []}, "description": "Wait for a while."}
`;

const createPROMPT2 = (description: string) => {
  return `You are an agent designed to accomplish tasks.
${description}
<seed:cot_budget_reflect>${think_budget}</seed:cot_budget_reflect>`;
};

/** 3.1 Think Prompt */
const PROMPT1 = use_native_thinking
  ? ``
  : `You should first think about the reasoning process in the mind and then provide the user with the answer. The reasoning process is enclosed within <${think_token}> </${think_token}> tags, i.e. <${think_token}> reasoning process here </${think_token}> answer here`;

/** 3.2 Role/Task Prompt */

/** 3.3 Action/Function Definition Prompt (如果没有functions则不需要这段prompt) */
const createPROMPT3 = (functions: string[], additionalNotes: string) => `## Function Definition

- You have access to the following functions:
${functions.join('')}

- To call a function, use the following structure without any suffix:

<${think_token}> reasoning process </${think_token}>
<seed:tool_call>
<function=example_function_name>
<parameter=example_parameter_1>value_1</parameter>
<parameter=example_parameter_2>
This is the value for the second parameter
that can span
multiple lines
</parameter>
</function>
</seed:tool_call>

## Important Notes
- Function calls must begin with <function= and end with </function>.
- All required parameters must be explicitly provided.

## Additional Notes
${additionalNotes}
`;

// Default SYSTEM_PROMPT_GROUP for backwards compatibility (omni mode)
export const SYSTEM_PROMPT_GROUP = [
  PROMPT1,
  createPROMPT2(task_description),
  createPROMPT3([mcp_functions, code_functions, gui_functions], omni_additional_notes),
];

/**
 * Create system prompt group based on agent mode
 * @param agentMode - The agent mode ('omni' or 'gui')
 * @returns Array of prompt strings
 */
export const createSystemPromptGroup = (agentMode: AgentMode): string[] => {
  logger.info('agentMode: ', agentMode);

  switch (agentMode.id) {
    case 'omni':
      return SYSTEM_PROMPT_GROUP;
    case 'gui':
      return [
        PROMPT1,
        createPROMPT2(gui_task_description),
        createPROMPT3([gui_functions], gui_additional_notes),
      ];
    case 'game':
      return [
        PROMPT1,
        createPROMPT2(game_task_description),
        createPROMPT3([game_functions], gui_additional_notes),
      ];
  }

  return [];
};
