import asyncio
from typing import Dict, Any, List

from clawagents.tools.registry import Tool, ToolResult

DEFAULT_TIMEOUT_MS = 30000
MAX_OUTPUT_CHARS = 10000

class ExecTool:
    name = "execute"
    description = "Execute a shell command and return its output. Use for running scripts, installing packages, checking system state, etc. Commands run in the current working directory."
    parameters = {
        "command": {"type": "string", "description": "The shell command to execute", "required": True},
        "timeout": {"type": "number", "description": f"Timeout in milliseconds. Default: {DEFAULT_TIMEOUT_MS}"}
    }

    async def execute(self, args: Dict[str, Any]) -> ToolResult:
        command = str(args.get("command", ""))
        timeout_ms = int(args.get("timeout", DEFAULT_TIMEOUT_MS))

        if not command:
            return ToolResult(success=False, output="", error="No command provided")

        blocked = ["rm -rf /", "mkfs", "dd if=", "> /dev/sd"]
        for pattern in blocked:
            if pattern in command:
                return ToolResult(success=False, output="", error=f"Blocked potentially destructive command: {command}")

        try:
            proc = await asyncio.create_subprocess_shell(
                command,
                stdout=asyncio.subprocess.PIPE,
                stderr=asyncio.subprocess.PIPE,
                env={"PAGER": "cat"}
            )

            try:
                stdout_bytes, stderr_bytes = await asyncio.wait_for(proc.communicate(), timeout=timeout_ms / 1000.0)
            except asyncio.TimeoutError:
                proc.kill()
                return ToolResult(success=False, output="", error=f"Command timed out after {timeout_ms}ms: {command}")

            stdout = stdout_bytes.decode("utf-8", errors="replace")
            stderr = stderr_bytes.decode("utf-8", errors="replace")

            output = stdout or ""
            if stderr:
                output += ("\n" if output else "") + f"[stderr] {stderr}"

            if len(output) > MAX_OUTPUT_CHARS:
                half = MAX_OUTPUT_CHARS // 2
                output = output[:half] + f"\n\n... [truncated {len(output) - MAX_OUTPUT_CHARS} chars] ...\n\n" + output[-half:]

            return ToolResult(success=True, output=output or "(no output)")

        except Exception as e:
            return ToolResult(success=False, output="", error=f"Command failed: {str(e)}")

exec_tools: List[Tool] = [ExecTool()]
