"""
Bash Tool - 命令执行工具

参考 OpenCode bash.ts 完整实现。

核心功能：
- 执行 shell 命令
- 超时控制
- 工作目录设置
- 环境变量传递
"""

import subprocess
import asyncio
from pathlib import Path
from typing import Optional, Dict

from agent.tools import tool, ToolResult, ToolContext

# 常量
DEFAULT_TIMEOUT = 120  # 2 分钟
MAX_OUTPUT_LENGTH = 50000  # 最大输出长度


@tool(description="执行 bash 命令")
async def bash_command(
    command: str,
    timeout: Optional[int] = None,
    workdir: Optional[str] = None,
    env: Optional[Dict[str, str]] = None,
    description: str = "",
    context: Optional[ToolContext] = None
) -> ToolResult:
    """
    执行 bash 命令

    Args:
        command: 要执行的命令
        timeout: 超时时间（秒），默认 120 秒
        workdir: 工作目录，默认为当前目录
        env: 环境变量字典（会合并到系统环境变量）
        description: 命令描述（5-10 个词）
        context: 工具上下文

    Returns:
        ToolResult: 命令输出
    """
    # 参数验证
    if timeout is not None and timeout < 0:
        return ToolResult(
            title="参数错误",
            output=f"无效的 timeout 值: {timeout}。必须是正数。",
            error="Invalid timeout"
        )

    timeout_sec = timeout or DEFAULT_TIMEOUT

    # 工作目录
    cwd = Path(workdir) if workdir else Path.cwd()
    if not cwd.exists():
        return ToolResult(
            title="目录不存在",
            output=f"工作目录不存在: {workdir}",
            error="Directory not found"
        )

    # 准备环境变量
    import os
    process_env = os.environ.copy()
    if env:
        process_env.update(env)

    # 执行命令
    try:
        process = await asyncio.create_subprocess_shell(
            command,
            stdout=asyncio.subprocess.PIPE,
            stderr=asyncio.subprocess.PIPE,
            cwd=str(cwd),
            env=process_env
        )

        # 等待命令完成（带超时）
        try:
            stdout, stderr = await asyncio.wait_for(
                process.communicate(),
                timeout=timeout_sec
            )
        except asyncio.TimeoutError:
            # 超时，终止进程
            process.kill()
            await process.wait()
            return ToolResult(
                title="命令超时",
                output=f"命令执行超时（>{timeout_sec}s）: {command[:100]}",
                error="Timeout",
                metadata={"command": command, "timeout": timeout_sec}
            )

        # 解码输出
        stdout_text = stdout.decode('utf-8', errors='replace') if stdout else ""
        stderr_text = stderr.decode('utf-8', errors='replace') if stderr else ""

        # 截断过长输出
        truncated = False
        if len(stdout_text) > MAX_OUTPUT_LENGTH:
            stdout_text = stdout_text[:MAX_OUTPUT_LENGTH] + f"\n\n(输出被截断，总长度: {len(stdout_text)} 字符)"
            truncated = True

        # 组合输出
        output = ""
        if stdout_text:
            output += stdout_text

        if stderr_text:
            if output:
                output += "\n\n--- stderr ---\n"
            output += stderr_text

        if not output:
            output = "(命令无输出)"

        # 检查退出码
        exit_code = process.returncode
        success = exit_code == 0

        title = description or f"命令: {command[:50]}"
        if not success:
            title += f" (exit code: {exit_code})"

        return ToolResult(
            title=title,
            output=output,
            metadata={
                "exit_code": exit_code,
                "success": success,
                "truncated": truncated,
                "command": command,
                "cwd": str(cwd)
            },
            error=None if success else f"Command failed with exit code {exit_code}"
        )

    except Exception as e:
        return ToolResult(
            title="执行错误",
            output=f"命令执行失败: {str(e)}",
            error=str(e),
            metadata={"command": command}
        )
