# tests/test_toolset_openai_agents.py
from __future__ import annotations

import json

import pytest

agents_mod = pytest.importorskip("agents")

from unittest.mock import AsyncMock, MagicMock  # noqa: E402

from agentsh_secure_sandbox.toolset.openai_agents import SecureSandboxAgentTools  # noqa: E402


async def test_agent_tools_get_tools_returns_three(monkeypatch):
    mock_secure = AsyncMock(return_value=AsyncMock())
    monkeypatch.setattr(
        "agentsh_secure_sandbox.toolset._base.secure_sandbox", mock_secure,
    )
    tools = SecureSandboxAgentTools(MagicMock())
    async with tools:
        tool_list = tools.get_tools()
    assert len(tool_list) == 3
    names = {t.name for t in tool_list}
    assert names == {"run_command", "write_file", "read_file"}


async def test_agent_tools_are_function_tool(monkeypatch):
    from agents import FunctionTool

    mock_secure = AsyncMock(return_value=AsyncMock())
    monkeypatch.setattr(
        "agentsh_secure_sandbox.toolset._base.secure_sandbox", mock_secure,
    )
    tools = SecureSandboxAgentTools(MagicMock())
    async with tools:
        for tool in tools.get_tools():
            assert isinstance(tool, FunctionTool)


async def test_run_command_invoke(monkeypatch):
    mock_sandbox = AsyncMock()
    mock_sandbox.exec = AsyncMock(return_value=MagicMock(
        exit_code=0, stdout="hello\n", stderr="",
    ))
    mock_secure = AsyncMock(return_value=mock_sandbox)
    monkeypatch.setattr(
        "agentsh_secure_sandbox.toolset._base.secure_sandbox", mock_secure,
    )
    tools = SecureSandboxAgentTools(MagicMock())
    async with tools:
        tool_map = {t.name: t for t in tools.get_tools()}
        ctx = MagicMock()
        result = await tool_map["run_command"].on_invoke_tool(
            ctx, json.dumps({"command": "echo hello"}),
        )
    assert result == "hello\n"


async def test_write_file_invoke(monkeypatch):
    mock_sandbox = AsyncMock()
    mock_sandbox.write_file = AsyncMock(return_value=MagicMock(
        success=True, path="/workspace/test.txt",
    ))
    mock_secure = AsyncMock(return_value=mock_sandbox)
    monkeypatch.setattr(
        "agentsh_secure_sandbox.toolset._base.secure_sandbox", mock_secure,
    )
    tools = SecureSandboxAgentTools(MagicMock())
    async with tools:
        tool_map = {t.name: t for t in tools.get_tools()}
        ctx = MagicMock()
        result = await tool_map["write_file"].on_invoke_tool(
            ctx, json.dumps({"path": "/workspace/test.txt", "content": "hi"}),
        )
    assert "Written to" in result


async def test_read_file_invoke(monkeypatch):
    mock_sandbox = AsyncMock()
    mock_sandbox.read_file = AsyncMock(return_value=MagicMock(
        success=True, content="file content",
    ))
    mock_secure = AsyncMock(return_value=mock_sandbox)
    monkeypatch.setattr(
        "agentsh_secure_sandbox.toolset._base.secure_sandbox", mock_secure,
    )
    tools = SecureSandboxAgentTools(MagicMock())
    async with tools:
        tool_map = {t.name: t for t in tools.get_tools()}
        ctx = MagicMock()
        result = await tool_map["read_file"].on_invoke_tool(
            ctx, json.dumps({"path": "/workspace/test.txt"}),
        )
    assert result == "file content"


def test_agent_tools_sandbox_not_provisioned():
    tools = SecureSandboxAgentTools(MagicMock())
    with pytest.raises(RuntimeError, match="not provisioned"):
        _ = tools.sandbox


async def test_get_tools_does_not_mutate_tool_defs(monkeypatch):
    """FunctionTool.__post_init__ calls ensure_strict_json_schema which mutates
    dicts in place. Verify we deep-copy so TOOL_DEFS stays intact."""
    from agentsh_secure_sandbox.toolset._base import TOOL_DEFS
    import copy

    original = copy.deepcopy(TOOL_DEFS)

    mock_secure = AsyncMock(return_value=AsyncMock())
    monkeypatch.setattr(
        "agentsh_secure_sandbox.toolset._base.secure_sandbox", mock_secure,
    )
    tools = SecureSandboxAgentTools(MagicMock())
    async with tools:
        tools.get_tools()

    assert TOOL_DEFS == original
