# src/agentsh_secure_sandbox/toolset/_base.py
from __future__ import annotations
from typing import Any
from typing_extensions import Self

from ..core.types import SecuredSandbox, SandboxAdapter, SecureConfig
from .._api import secure_sandbox


# Tool metadata shared by all framework integrations.
TOOL_DEFS: dict[str, dict[str, Any]] = {
    "run_command": {
        "name": "run_command",
        "description": (
            "Execute a shell command in the secure sandbox. "
            "All commands are mediated by security policy. "
            "Dangerous operations (reading secrets, network exfiltration, "
            "privilege escalation) will be blocked."
        ),
        "parameters": {
            "type": "object",
            "properties": {
                "command": {
                    "type": "string",
                    "description": "Shell command to execute",
                },
                "cwd": {
                    "type": "string",
                    "description": "Working directory (default: /workspace)",
                },
            },
            "required": ["command"],
            "additionalProperties": False,
        },
    },
    "write_file": {
        "name": "write_file",
        "description": (
            "Write content to a file in the secure sandbox. "
            "Writes to sensitive paths (secrets, config files) "
            "will be blocked by policy."
        ),
        "parameters": {
            "type": "object",
            "properties": {
                "path": {
                    "type": "string",
                    "description": "File path to write",
                },
                "content": {
                    "type": "string",
                    "description": "File content",
                },
            },
            "required": ["path", "content"],
            "additionalProperties": False,
        },
    },
    "read_file": {
        "name": "read_file",
        "description": (
            "Read a file from the secure sandbox. "
            "Reads from sensitive paths (secrets, credentials) "
            "will be blocked by policy."
        ),
        "parameters": {
            "type": "object",
            "properties": {
                "path": {
                    "type": "string",
                    "description": "File path to read",
                },
            },
            "required": ["path"],
            "additionalProperties": False,
        },
    },
}


class SecureSandboxTools:
    """Framework-agnostic secure sandbox tool provider.

    Owns the adapter -> SecuredSandbox lifecycle.
    Subclassed or composed by framework-specific integrations.
    """

    def __init__(
        self,
        adapter: SandboxAdapter,
        config: SecureConfig | None = None,
    ) -> None:
        self._adapter = adapter
        self._config = config or SecureConfig()
        self._sandbox: SecuredSandbox | None = None

    async def __aenter__(self) -> Self:
        self._sandbox = await secure_sandbox(self._adapter, self._config)
        return self

    async def __aexit__(self, *args: Any) -> None:
        if self._sandbox:
            await self._sandbox.stop()
            self._sandbox = None

    @property
    def sandbox(self) -> SecuredSandbox:
        if self._sandbox is None:
            raise RuntimeError(
                "Sandbox not provisioned. Use 'async with' to enter the context."
            )
        return self._sandbox

    async def call_tool(self, name: str, args: dict[str, Any]) -> str:
        """Execute a tool call against the secured sandbox.

        Returns a string result suitable for returning to the LLM.
        """
        sb = self.sandbox

        if name == "run_command":
            result = await sb.exec(
                args["command"],
                cwd=args.get("cwd"),
            )
            if result.exit_code != 0:
                parts = [f"Command failed (exit {result.exit_code}):"]
                if result.stdout:
                    parts.append(f"stdout:\n{result.stdout}")
                if result.stderr:
                    parts.append(f"stderr:\n{result.stderr}")
                return "\n".join(parts)
            return result.stdout

        if name == "write_file":
            write_result = await sb.write_file(args["path"], args["content"])
            if write_result.success:
                return f"Written to {write_result.path}"
            return f"Write denied: {write_result.error}"

        if name == "read_file":
            read_result = await sb.read_file(args["path"])
            if read_result.success:
                return read_result.content
            return f"Read denied: {read_result.error}"

        raise ValueError(f"Unknown tool: {name}")
