"""Tests for CAMEL framework."""

import pytest
from camel import (
    RolePlayingAgent,
    AgentRole,
    Conversation,
    Message,
    MessageRole,
    CAMELSociety,
    SocietyResult,
    Role,
    AgentType,
    Task,
    DEFAULT_ROLES,
)


class TestRole:
    """Test Role dataclass."""

    def test_role_creation(self):
        role = Role(name="Test Role", description="A test role")
        assert role.name == "Test Role"
        assert role.agent_type == AgentType.ASSISTANT

    def test_role_system_prompt(self):
        role = Role(name="Programmer", description="Writes code")
        prompt = role.get_system_prompt()
        assert "Programmer" in prompt
        assert "Writes code" in prompt

    def test_role_to_dict(self):
        role = Role(name="Test", description="Desc", role_id="r1")
        d = role.to_dict()
        assert d["name"] == "Test"
        assert d["role_id"] == "r1"


class TestMessage:
    """Test Message dataclass."""

    def test_message_creation(self):
        msg = Message(content="Hello", role=MessageRole.USER, sender_name="Alice")
        assert msg.content == "Hello"
        assert msg.role == MessageRole.USER
        assert msg.sender_name == "Alice"

    def test_message_to_openai_format(self):
        msg = Message(content="Test", role=MessageRole.ASSISTANT)
        formatted = msg.to_openai_format()
        assert formatted["role"] == "assistant"
        assert formatted["content"] == "Test"

    def test_message_to_dict(self):
        msg = Message(content="Test", role=MessageRole.USER, message_id="m1")
        d = msg.to_dict()
        assert d["content"] == "Test"
        assert d["message_id"] == "m1"


class TestConversation:
    """Test Conversation class."""

    def test_conversation_creation(self):
        conv = Conversation()
        assert conv.count_messages() == 0

    def test_add_message(self):
        conv = Conversation()
        msg = conv.add_message("Hello", MessageRole.USER, "Alice")
        assert conv.count_messages() == 1
        assert msg.content == "Hello"

    def test_get_openai_messages(self):
        conv = Conversation()
        conv.add_message("System", MessageRole.SYSTEM)
        conv.add_message("Hi", MessageRole.USER)
        conv.add_message("Hello!", MessageRole.ASSISTANT)

        messages = conv.get_openai_messages()
        assert len(messages) == 3

    def test_get_context_string(self):
        conv = Conversation()
        conv.add_message("Msg1", MessageRole.USER, "User")
        conv.add_message("Msg2", MessageRole.ASSISTANT, "Assistant")

        context = conv.get_context_string()
        assert "Msg1" in context
        assert "Msg2" in context

    def test_max_turns(self):
        conv = Conversation(max_turns=2)
        conv.add_message("1", MessageRole.USER)
        conv.add_message("2", MessageRole.ASSISTANT)
        assert conv.is_complete()


class TestRolePlayingAgent:
    """Test RolePlayingAgent class."""

    def test_agent_creation(self):
        role = Role(name="Tester", description="Tests things")
        agent = RolePlayingAgent(role=role)
        assert agent.role.name == "Tester"

    def test_agent_respond(self):
        role = Role(name="Bot", description="A bot")
        agent = RolePlayingAgent(role=role)

        response = agent.respond("Hello!")
        assert response.content != ""
        assert response.sender_name == "Bot"

    def test_agent_with_custom_respond_fn(self):
        def custom_fn(context, messages):
            return "Custom response"

        role = Role(name="Custom", description="Custom agent")
        agent = RolePlayingAgent(role=role, respond_fn=custom_fn)

        response = agent.respond("Test")
        assert response.content == "Custom response"


class TestCAMELSociety:
    """Test CAMELSociety class."""

    def test_society_creation(self):
        society = CAMELSociety()
        assert len(society.get_agents()) == 0

    def test_add_agent(self):
        society = CAMELSociety()
        role = Role(name="Agent1", description="First agent")
        agent = society.add_agent(role)

        assert len(society.get_agents()) == 1
        assert agent.role.name == "Agent1"

    def test_collaborate_needs_two_agents(self):
        society = CAMELSociety()
        society.add_agent(Role(name="A1", description="First"))

        with pytest.raises(ValueError):
            society.collaborate("Test task")

    def test_collaborate(self):
        society = CAMELSociety(max_turns=2)
        role1 = Role(name="A1", description="First", agent_type=AgentType.ASSISTANT)
        role2 = Role(name="A2", description="Second", agent_type=AgentType.USER)

        result = society.collaborate("Test task", agents=[role1, role2])

        assert result.success is True
        assert result.total_turns > 0

    def test_quick_collaborate(self):
        society = CAMELSociety(max_turns=2)
        result = society.quick_collaborate("Write code", "programmer", "reviewer")

        assert result.success is True
        assert "Programmer" in result.agent_contributions or "Python Programmer" in result.agent_contributions

    def test_society_result_to_dict(self):
        society = CAMELSociety(max_turns=2)
        result = society.quick_collaborate("Test")

        d = result.to_dict()
        assert "success" in d
        assert "total_turns" in d


class TestDefaultRoles:
    """Test predefined roles."""

    def test_default_roles_exist(self):
        assert "programmer" in DEFAULT_ROLES
        assert "reviewer" in DEFAULT_ROLES
        assert "teacher" in DEFAULT_ROLES
        assert "student" in DEFAULT_ROLES

    def test_default_role_types(self):
        programmer = DEFAULT_ROLES["programmer"]
        assert programmer.agent_type == AgentType.ASSISTANT

        reviewer = DEFAULT_ROLES["reviewer"]
        assert reviewer.agent_type == AgentType.USER


class TestTask:
    """Test Task dataclass."""

    def test_task_creation(self):
        task = Task(description="Test task")
        assert task.description == "Test task"
        assert task.task_id is not None

    def test_task_to_dict(self):
        task = Task(description="Test", task_id="t1")
        d = task.to_dict()
        assert d["description"] == "Test"
        assert d["task_id"] == "t1"