import unittest
from unittest.mock import Mock
from analogai.foundation.modules.agent.agent import Agent, Role
from analogai.foundation.modules.user.user import User
from analogai.foundation.common.enums.agent_openness import AgentOpenness
from analogai.foundation.modules.agent.agent_service import AgentService
from analogai.foundation.modules.agent.agent_repository import AgentRepository


class TestAgentService(unittest.TestCase):

    def setUp(self):
        self.mock_repository = Mock(spec=AgentRepository)
        self.service = AgentService(self.mock_repository)

        self.test_user = User(id="user_123", name="Test User", email="test@example.com")
        self.test_agent = Agent(
            id="agent_456",
            knowledge_base="Test knowledge base",
            creator=self.test_user,
            roles=[]
        )

    def test_find_existing_agent(self):
        self.mock_repository.find_by_id.return_value = self.test_agent

        result = self.service.find("agent_456")

        self.assertEqual(result, self.test_agent)
        self.mock_repository.find_by_id.assert_called_once_with("agent_456")

    def test_find_nonexistent_agent(self):
        self.mock_repository.find_by_id.return_value = None

        result = self.service.find("nonexistent")

        self.assertIsNone(result)
        self.mock_repository.find_by_id.assert_called_once_with("nonexistent")

    def test_get_agents_by_creator_with_agents(self):
        another_agent = Agent(
            id="agent_789",
            knowledge_base="Another knowledge base",
            creator=self.test_user,
            roles=[]
        )

        self.mock_repository.find_by_creator_id.return_value = [self.test_agent, another_agent]

        result = self.service.get_agents_by_creator("user_123")

        self.assertEqual(len(result), 2)
        self.assertIn(self.test_agent, result)
        self.assertIn(another_agent, result)
        self.mock_repository.find_by_creator_id.assert_called_once_with("user_123")

    def test_get_agents_by_creator_no_agents(self):
        self.mock_repository.find_by_creator_id.return_value = []

        result = self.service.get_agents_by_creator("user_123")

        self.assertEqual(len(result), 0)
        self.mock_repository.find_by_creator_id.assert_called_once_with("user_123")

    def test_create_agent_with_all_parameters(self):
        roles = [Role(user=self.test_user, authority=0.8)]
        self.mock_repository.create.return_value = self.test_agent

        result = self.service.create(
            creator=self.test_user,
            id="agent_456",
            name="Test Agent",
            knowledge_base="Test knowledge base",
            roles=roles
        )

        self.assertEqual(result, self.test_agent)
        self.mock_repository.create.assert_called_once()

        created_agent = self.mock_repository.create.call_args[0][0]
        self.assertEqual(created_agent.id, "agent_456")
        self.assertEqual(created_agent.name, "Test Agent")
        self.assertEqual(created_agent.knowledge_base, "Test knowledge base")
        self.assertEqual(created_agent.creator, self.test_user)
        self.assertEqual(created_agent.roles, roles)

    def test_create_agent_with_minimal_parameters(self):
        self.mock_repository.create.return_value = self.test_agent

        result = self.service.create(id="agent_456", creator=self.test_user)

        self.assertEqual(result, self.test_agent)
        self.mock_repository.create.assert_called_once()

        created_agent = self.mock_repository.create.call_args[0][0]
        self.assertEqual(created_agent.id, "agent_456")
        self.assertEqual(created_agent.name, "")
        self.assertEqual(created_agent.knowledge_base, "")
        self.assertEqual(created_agent.creator, self.test_user)
        self.assertEqual(created_agent.roles, [])

    def test_create_agent_with_default_roles(self):
        self.mock_repository.create.return_value = self.test_agent

        result = self.service.create(
            creator=self.test_user,
            id="agent_456",
            knowledge_base="Test knowledge base",
            roles=None
        )

        self.assertEqual(result, self.test_agent)
        self.mock_repository.create.assert_called_once()

        created_agent = self.mock_repository.create.call_args[0][0]
        self.assertEqual(created_agent.roles, [])

    def test_create_agent_with_empty_roles(self):
        self.mock_repository.create.return_value = self.test_agent

        result = self.service.create(
            creator=self.test_user,
            id="agent_456",
            knowledge_base="Test knowledge base",
            roles=[]
        )

        self.assertEqual(result, self.test_agent)
        self.mock_repository.create.assert_called_once()

        created_agent = self.mock_repository.create.call_args[0][0]
        self.assertEqual(created_agent.roles, [])

    def test_create_agent_with_name(self):
        self.mock_repository.create.return_value = self.test_agent

        result = self.service.create(
            creator=self.test_user,
            id="agent_456",
            name="My Test Agent",
            knowledge_base="Test knowledge base"
        )

        self.assertEqual(result, self.test_agent)
        self.mock_repository.create.assert_called_once()

        created_agent = self.mock_repository.create.call_args[0][0]
        self.assertEqual(created_agent.name, "My Test Agent")

    def test_update_agent_success(self):
        updated_agent = Agent(
            id="agent_456",
            knowledge_base="Updated knowledge base",
            creator=self.test_user,
            roles=[]
        )
        self.mock_repository.update.return_value = updated_agent

        result = self.service.update(updated_agent)

        self.assertEqual(result, updated_agent)
        self.mock_repository.update.assert_called_once_with(updated_agent)

    def test_update_agent_with_roles(self):
        role = Role(user=self.test_user, authority=0.9)
        updated_agent = Agent(
            id="agent_456",
            knowledge_base="Updated knowledge base",
            creator=self.test_user,
            roles=[role]
        )
        self.mock_repository.update.return_value = updated_agent

        result = self.service.update(updated_agent)

        self.assertEqual(result, updated_agent)
        self.mock_repository.update.assert_called_once_with(updated_agent)

    def test_delete_agent_success(self):
        self.mock_repository.delete.return_value = True

        result = self.service.delete("agent_456")

        self.assertTrue(result)
        self.mock_repository.delete.assert_called_once_with("agent_456")

    def test_delete_agent_failure(self):
        self.mock_repository.delete.return_value = False

        result = self.service.delete("nonexistent_agent")

        self.assertFalse(result)
        self.mock_repository.delete.assert_called_once_with("nonexistent_agent")

    def test_delete_agent_with_empty_id(self):
        self.mock_repository.delete.return_value = False

        result = self.service.delete("")

        self.assertFalse(result)
        self.mock_repository.delete.assert_called_once_with("")

    def test_agent_openness_functionality(self):
        agent = Agent(
            id="agent_123",
            knowledge_base="Test knowledge base",
            creator=self.test_user,
            roles=[]
        )

        self.assertTrue(agent.is_open())
        self.assertFalse(agent.is_closed())

        agent.set_openness(AgentOpenness.CLOSED)
        self.assertFalse(agent.is_open())
        self.assertTrue(agent.is_closed())

        agent.set_openness(AgentOpenness.OPEN)
        self.assertTrue(agent.is_open())
        self.assertFalse(agent.is_closed())

    def test_agent_default_values(self):
        agent = Agent(id="agent_123", creator=self.test_user)

        self.assertEqual(agent.name, "")
        self.assertEqual(agent.knowledge_base, "")
        self.assertEqual(agent.creator, self.test_user)
        self.assertEqual(agent.roles, [])
        self.assertEqual(agent.openness, AgentOpenness.OPEN)


if __name__ == '__main__':
    unittest.main()
