from __future__ import annotations

import pytest
import respx
import httpx
from unittest.mock import MagicMock

from surfinguard import Guard, Policy
from surfinguard.exceptions import NotAllowedError
from surfinguard.integrations.langchain import SurfinguardToolGuard, _infer_action_type

import sys
import os
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))
from conftest import SAFE_RESPONSE, DANGER_RESPONSE


@pytest.fixture()
def mock_api():
    with respx.mock(base_url="https://test.surfinguard.com", assert_all_called=False) as api:
        yield api


@pytest.fixture()
def guard():
    return Guard(
        api_key="sg_test_0123456789abcdef0123456789abcdef",
        base_url="https://test.surfinguard.com",
        policy=Policy.MODERATE,
    )


class TestToolGuard:
    def test_wrap_allows_safe(self, mock_api, guard):
        mock_api.post("/v2/check").mock(
            return_value=httpx.Response(200, json=SAFE_RESPONSE)
        )
        tool = MagicMock()
        tool.name = "shell_executor"
        tool._run = MagicMock(return_value="output")

        tool_guard = SurfinguardToolGuard(guard)
        wrapped = tool_guard.wrap(tool)
        result = wrapped._run("ls -la")
        assert result == "output"

    def test_wrap_blocks_dangerous(self, mock_api, guard):
        mock_api.post("/v2/check").mock(
            return_value=httpx.Response(200, json=DANGER_RESPONSE)
        )
        tool = MagicMock()
        tool.name = "shell_executor"
        tool._run = MagicMock(return_value="output")

        tool_guard = SurfinguardToolGuard(guard)
        wrapped = tool_guard.wrap(tool)
        with pytest.raises(NotAllowedError):
            wrapped._run("rm -rf /")

    def test_wrap_all(self, mock_api, guard):
        mock_api.post("/v2/check").mock(
            return_value=httpx.Response(200, json=SAFE_RESPONSE)
        )
        tool1 = MagicMock()
        tool1.name = "tool1"
        tool1._run = MagicMock(return_value="a")
        tool2 = MagicMock()
        tool2.name = "tool2"
        tool2._run = MagicMock(return_value="b")

        tool_guard = SurfinguardToolGuard(guard)
        wrapped = tool_guard.wrap_all([tool1, tool2])
        assert len(wrapped) == 2

    def test_action_type_override(self, mock_api, guard):
        route = mock_api.post("/v2/check").mock(
            return_value=httpx.Response(200, json=SAFE_RESPONSE)
        )
        tool = MagicMock()
        tool.name = "generic"
        tool._run = MagicMock(return_value="ok")

        tool_guard = SurfinguardToolGuard(guard)
        tool_guard.wrap(tool, action_type="url")
        tool._run("https://example.com")
        import json
        body = json.loads(route.calls[0].request.content)
        assert body["type"] == "url"


class TestInferActionType:
    def test_url_keywords(self):
        assert _infer_action_type("browse_web") == "url"
        assert _infer_action_type("fetch_url") == "url"

    def test_command_keywords(self):
        assert _infer_action_type("shell_executor") == "command"
        assert _infer_action_type("bash_tool") == "command"

    def test_file_keywords(self):
        assert _infer_action_type("file_writer") == "file_write"
        assert _infer_action_type("read_file") == "file_read"

    def test_default_command(self):
        assert _infer_action_type("unknown_tool") == "command"
