import pytest
from langchain_core.tools import BaseTool
from interceptor import Interceptor, Mode, DecisionVerdict
from interceptor.integrations.langchain import InterceptedTool

# --- Mock Tools ---

class CalculatorTool(BaseTool):
    name: str = "calculator"
    description: str = "Adds two numbers."

    def _run(self, a: int, b: int, **kwargs) -> int:
        return a + b

    async def _arun(self, a: int, b: int, **kwargs) -> int:
        return a + b

class DeleteTool(BaseTool):
    name: str = "delete_database"
    description: str = "Deletes the DB."
    def _run(self, db_name: str, **kwargs) -> str: return "Deleted"

class WipeTool(BaseTool):
    name: str = "wipe_disk"
    description: str = "Wipes disk."
    def _run(self, drive: str, **kwargs) -> str: return "Wiped"
    async def _arun(self, drive: str, **kwargs) -> str: return "Wiped"

class WriteTool(BaseTool):
    name: str = "write_file"
    description: str = "Writes a file."
    def _run(self, path: str, content: str, **kwargs) -> str: return "Written"

# --- Tests ---

def test_langchain_sync_allowed():
    guard = Interceptor(mode=Mode.STRICT)
    safe_tool = InterceptedTool(tool=CalculatorTool(), guard=guard)
    
    result = safe_tool.run({"a": 1, "b": 2})
    assert result == 3

def test_langchain_sync_blocked():
    guard = Interceptor(mode=Mode.STRICT)
    danger_tool = InterceptedTool(tool=DeleteTool(), guard=guard)
    
    result = danger_tool.run({"db_name": "prod"})
    assert "BLOCKED" in result
    assert "destructive action" in result

@pytest.mark.asyncio
async def test_langchain_async_allowed():
    guard = Interceptor(mode=Mode.STRICT)
    safe_tool = InterceptedTool(tool=CalculatorTool(), guard=guard)
    
    result = await safe_tool.arun({"a": 10, "b": 20})
    assert result == 30

@pytest.mark.asyncio
async def test_langchain_async_blocked():
    guard = Interceptor(mode=Mode.STRICT)
    danger_tool = InterceptedTool(tool=WipeTool(), guard=guard)
    
    # "wipe" isn't a default keyword, but "delete" is.
    # Actually, let's just make sure the name triggers it or we use a keyword.
    # "delete" is a keyword.
    class DangerTool(BaseTool):
        name: str = "delete_all"
        description: str = "Delete everything."
        def _run(self, **kwargs): return "ok"
        async def _arun(self, **kwargs): return "ok"

    danger_tool = InterceptedTool(tool=DangerTool(), guard=guard)
    result = await danger_tool.arun({})
    assert "BLOCKED" in result

def test_langchain_confirmation_required():
    guard = Interceptor(mode=Mode.STRICT)
    warn_tool = InterceptedTool(tool=WriteTool(), guard=guard)
    
    # Use a path with / to trigger MEDIUM risk
    result = warn_tool.run({"path": "/app/config.yaml", "content": "hello"})
    assert "REQUIRES HUMAN CONFIRMATION" in result
    assert "write to /app/config.yaml" in result
