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.crewai import SurfinguardCrewGuard

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 TestCrewGuard:
    def test_check_tool_allows_safe(self, mock_api, guard):
        mock_api.post("/v2/check").mock(
            return_value=httpx.Response(200, json=SAFE_RESPONSE)
        )
        crew_guard = SurfinguardCrewGuard(guard)

        @crew_guard.check_tool("command")
        def run_cmd(cmd: str) -> str:
            return f"ran: {cmd}"

        result = run_cmd("ls")
        assert result == "ran: ls"

    def test_check_tool_blocks_dangerous(self, mock_api, guard):
        mock_api.post("/v2/check").mock(
            return_value=httpx.Response(200, json=DANGER_RESPONSE)
        )
        crew_guard = SurfinguardCrewGuard(guard)

        @crew_guard.check_tool("command")
        def run_cmd(cmd: str) -> str:
            return f"ran: {cmd}"

        with pytest.raises(NotAllowedError):
            run_cmd("rm -rf /")

    def test_step_callback_checks_tool_input(self, mock_api, guard):
        route = mock_api.post("/v2/check").mock(
            return_value=httpx.Response(200, json=SAFE_RESPONSE)
        )
        crew_guard = SurfinguardCrewGuard(guard)

        step = MagicMock()
        step.tool_input = "echo hello"

        crew_guard.step_callback(step)
        assert route.called

    def test_step_callback_ignores_non_tool_steps(self, mock_api, guard):
        route = mock_api.post("/v2/check").mock(
            return_value=httpx.Response(200, json=SAFE_RESPONSE)
        )
        crew_guard = SurfinguardCrewGuard(guard)

        step = MagicMock(spec=[])  # No tool_input attribute

        crew_guard.step_callback(step)
        assert not route.called
