"""
Unit tests for the TaskDelegator class.
"""

import pytest
from synqed import TaskDelegator


class TestTaskDelegator:
    """Tests for the TaskDelegator class."""
    
    def test_delegator_creation(self):
        """Test creating a task delegator."""
        delegator = TaskDelegator()
        
        assert delegator is not None
        assert len(delegator.list_agents()) == 0
    
    def test_register_agent(self, simple_agent):
        """Test registering an agent."""
        delegator = TaskDelegator()
        
        delegator.register_agent(agent=simple_agent)
        
        agents = delegator.list_agents()
        assert len(agents) == 1
        assert agents[0]["name"] == simple_agent.name
    
    def test_register_multiple_agents(self, simple_agent, recipe_agent):
        """Test registering multiple agents."""
        delegator = TaskDelegator()
        
        delegator.register_agent(agent=simple_agent)
        delegator.register_agent(agent=recipe_agent)
        
        agents = delegator.list_agents()
        assert len(agents) == 2
    
    def test_register_agent_by_url(self):
        """Test registering an agent by URL."""
        delegator = TaskDelegator()
        
        delegator.register_agent(agent_url="http://remote-agent:8000")
        
        agents = delegator.list_agents()
        assert len(agents) == 1
        assert agents[0]["url"] == "http://remote-agent:8000"
        assert agents[0]["is_local"] is False
    
    def test_register_without_agent_or_url(self):
        """Test that registering without agent or URL raises error."""
        delegator = TaskDelegator()
        
        with pytest.raises(ValueError, match="Must provide"):
            delegator.register_agent()
    
    def test_unregister_agent(self, simple_agent):
        """Test unregistering an agent."""
        delegator = TaskDelegator()
        
        delegator.register_agent(agent=simple_agent)
        assert len(delegator.list_agents()) == 1
        
        delegator.unregister_agent(simple_agent.name)
        assert len(delegator.list_agents()) == 0
    
    def test_list_agents(self, simple_agent, recipe_agent):
        """Test listing registered agents."""
        delegator = TaskDelegator()
        
        delegator.register_agent(agent=simple_agent)
        delegator.register_agent(agent=recipe_agent)
        
        agents = delegator.list_agents()
        
        assert len(agents) == 2
        assert all("id" in agent for agent in agents)
        assert all("url" in agent for agent in agents)
        assert all("is_local" in agent for agent in agents)
        assert all("name" in agent for agent in agents)
        assert all("skills" in agent for agent in agents)
    
    def test_delegator_repr(self):
        """Test delegator string representation."""
        delegator = TaskDelegator()
        
        repr_str = repr(delegator)
        
        assert "TaskDelegator" in repr_str
        assert "registered_agents=0" in repr_str
    
    @pytest.mark.asyncio
    async def test_submit_task(self, simple_server):
        """Test submitting a task."""
        delegator = TaskDelegator()
        delegator.register_agent(agent_url=simple_server.url)
        
        result = await delegator.submit_task("Test task")
        
        assert isinstance(result, str)
        assert len(result) > 0
        
        await delegator.close_all()
    
    @pytest.mark.asyncio
    async def test_submit_task_with_preferred_agent(self, simple_server):
        """Test submitting task with preferred agent."""
        delegator = TaskDelegator()
        delegator.register_agent(agent=simple_server.agent)
        
        result = await delegator.submit_task(
            "Test task",
            preferred_agent=simple_server.agent.name
        )
        
        assert isinstance(result, str)
        
        await delegator.close_all()
    
    @pytest.mark.asyncio
    async def test_submit_task_with_required_skills(self, recipe_server):
        """Test submitting task with required skills."""
        delegator = TaskDelegator()
        delegator.register_agent(agent=recipe_server.agent)
        
        result = await delegator.submit_task(
            "Make me dinner",
            require_skills=["cooking"]
        )
        
        assert isinstance(result, str)
        assert "Recipe" in result
        
        await delegator.close_all()
    
    @pytest.mark.asyncio
    async def test_submit_task_no_suitable_agent(self):
        """Test submitting task when no suitable agent exists."""
        delegator = TaskDelegator()
        
        with pytest.raises(ValueError, match="No suitable agent found"):
            await delegator.submit_task("Test task")
    
    @pytest.mark.asyncio
    async def test_submit_task_to_multiple(self, simple_server, recipe_server):
        """Test submitting task to multiple agents."""
        delegator = TaskDelegator()
        delegator.register_agent(agent=simple_server.agent)
        delegator.register_agent(agent=recipe_server.agent)
        
        results = await delegator.submit_task_to_multiple("Tell me about food")
        
        assert isinstance(results, dict)
        assert len(results) == 2
        
        # Each result should be a string
        for result in results.values():
            assert isinstance(result, str)
        
        await delegator.close_all()
    
    @pytest.mark.asyncio
    async def test_submit_task_to_specific_agents(self, simple_server, recipe_server):
        """Test submitting task to specific agents only."""
        delegator = TaskDelegator()
        delegator.register_agent(agent=simple_server.agent)
        delegator.register_agent(agent=recipe_server.agent)
        
        results = await delegator.submit_task_to_multiple(
            "Test task",
            agent_ids=[simple_server.agent.name]
        )
        
        assert isinstance(results, dict)
        assert len(results) == 1
        assert simple_server.agent.name in results
        
        await delegator.close_all()
    
    @pytest.mark.asyncio
    async def test_close_all_clients(self, simple_server):
        """Test closing all client connections."""
        delegator = TaskDelegator()
        delegator.register_agent(agent_url=simple_server.url)
        
        # Send a task to create a client
        await delegator.submit_task("Test")
        
        # Close all clients
        await delegator.close_all()

