"""Bash tool — execute shell commands."""

from __future__ import annotations

import asyncio
import os
from typing import Any

from pi_agents.agent.types import AgentTool, AgentToolResult
from pi_agents.ai.types import TextContent
from pi_agents.coding_agent.tools.truncate import truncate_tail


BASH_TOOL_NAME = "bash"
BASH_TOOL_DESCRIPTION = "Execute a bash command and return the output."

BASH_TOOL_PARAMETERS = {
    "type": "object",
    "properties": {
        "command": {"type": "string", "description": "The command to execute"},
        "timeout": {"type": "integer", "description": "Timeout in seconds"},
    },
    "required": ["command"],
}


def create_bash_tool(cwd: str | None = None) -> AgentTool:
    """Create a bash tool for executing commands."""

    class BashTool(AgentTool):
        def __init__(self) -> None:
            super().__init__(
                name=BASH_TOOL_NAME,
                description=BASH_TOOL_DESCRIPTION,
                parameters=BASH_TOOL_PARAMETERS,
            )
            self.label = "Bash"

        async def execute(
            self,
            tool_call_id: str,
            params: dict[str, Any],
            signal: Any = None,
            on_update: Any = None,
        ) -> AgentToolResult:
            command = params.get("command", "")
            timeout = params.get("timeout", 120)
            work_dir = cwd or os.getcwd()

            try:
                proc = await asyncio.create_subprocess_shell(
                    command,
                    stdout=asyncio.subprocess.PIPE,
                    stderr=asyncio.subprocess.STDOUT,
                    cwd=work_dir,
                )

                try:
                    stdout, _ = await asyncio.wait_for(proc.communicate(), timeout=timeout)
                    output = stdout.decode("utf-8", errors="replace") if stdout else ""
                    exit_code = proc.returncode
                except asyncio.TimeoutError:
                    proc.kill()
                    await proc.wait()
                    output = "Command timed out"
                    exit_code = None

            except Exception as e:
                output = str(e)
                exit_code = 1

            # Tail-truncate output
            tr = truncate_tail(output)
            details: dict[str, Any] = {"exitCode": exit_code}
            if tr.truncated:
                details["truncation"] = {
                    "truncated": True,
                    "truncatedBy": tr.truncated_by,
                    "totalLines": tr.total_lines,
                    "totalBytes": tr.total_bytes,
                }

            return AgentToolResult(
                content=[TextContent(type="text", text=tr.content)],
                details=details,
            )

    return BashTool()
