import pytest
from app.core.services.tool import ToolService

@pytest.mark.asyncio
async def test_mesh_file_explorer_none_path_and_session():
    """Test that UI tools don't crash when passing None for paths or unauthenticated session IDs."""
    from app.core.tools.definitions.mesh_file_explorer import MeshFileExplorerTool
    import app.core.services.tool as ts
    from unittest.mock import MagicMock
    
    # Mock services
    services_mock = MagicMock()
    # Mock orchestrator and mirror
    mirror_mock = MagicMock()
    mirror_mock.get_workspace_path.return_value = "/tmp/fake_workspace/__fs_explorer__"
    orchestrator_mock = MagicMock()
    orchestrator_mock.mirror = mirror_mock
    services_mock.orchestrator = orchestrator_mock
    
    # Init tool service wrapper purely to mimic the router context
    tool = MeshFileExplorerTool()
    
    # 1. Provide an empty context (simulating no active session attached to the UI call)
    context = {
        "services": services_mock,
        "session_id": "__fs_explorer__",
        "node_id": "hub" # Execute on hub to hit the _hub_fs branch
    }
    
    # Arguments where path is None
    args = {
        "action": "list",
        "path": None
    }
    
    task_fn, task_args = tool.prepare_task(args, context)
    assert task_fn is not None
    
    # Execute the synchronous task returned by the plugin
    result = task_fn(**task_args)
    
    # It shouldn't crash with TypeError. It might error with "Path not found" which is handled.
    assert "error" in result or "files" in result

@pytest.mark.asyncio
async def test_tool_service_node_id_validation():
    """Test that ToolService rejects unauthorized/hallucinated node IDs."""
    from unittest.mock import MagicMock
    
    service = ToolService()
    
    # Mock DB session and Session object
    db_mock = MagicMock()
    session_obj = MagicMock()
    session_obj.attached_node_ids = ["test-node-1"] 
    db_mock.query().filter().first.return_value = session_obj
    
    # We don't even need the dummy_skill, call_tool will block it early!
    
    # The AI guessed "node1"
    args = {"node_id": "node1"}
    
    res = await service.call_tool(
        tool_name="dummy_skill",
        arguments=args,
        db=db_mock,
        session_db_id=1
    )
    
    assert res.get("success") is False
    assert "NOT attached or doesn't exist" in res.get("error")
