# tests/models/syndarix/test_agent_type.py
"""
Unit tests for the AgentType model.
"""

import uuid
from datetime import datetime

import pytest
from sqlalchemy.exc import IntegrityError

from app.models.syndarix import AgentType


class TestAgentTypeModel:
    """Tests for AgentType model creation and fields."""

    def test_create_agent_type_with_required_fields(self, db_session):
        """Test creating an agent type with only required fields."""
        agent_type = AgentType(
            id=uuid.uuid4(),
            name="Test Agent",
            slug="test-agent",
            personality_prompt="You are a helpful assistant.",
            primary_model="claude-opus-4-5-20251101",
        )
        db_session.add(agent_type)
        db_session.commit()

        retrieved = db_session.query(AgentType).filter_by(slug="test-agent").first()

        assert retrieved is not None
        assert retrieved.name == "Test Agent"
        assert retrieved.slug == "test-agent"
        assert retrieved.personality_prompt == "You are a helpful assistant."
        assert retrieved.primary_model == "claude-opus-4-5-20251101"
        assert retrieved.is_active is True  # Default
        assert retrieved.expertise == []  # Default empty list
        assert retrieved.fallback_models == []  # Default empty list
        assert retrieved.model_params == {}  # Default empty dict
        assert retrieved.mcp_servers == []  # Default empty list
        assert retrieved.tool_permissions == {}  # Default empty dict

    def test_create_agent_type_with_all_fields(self, db_session):
        """Test creating an agent type with all optional fields."""
        agent_type_id = uuid.uuid4()

        agent_type = AgentType(
            id=agent_type_id,
            name="Full Agent Type",
            slug="full-agent-type",
            description="A fully configured agent type",
            expertise=["python", "fastapi", "testing"],
            personality_prompt="You are an expert Python developer...",
            primary_model="claude-opus-4-5-20251101",
            fallback_models=["claude-sonnet-4-20250514", "gpt-4o"],
            model_params={"temperature": 0.7, "max_tokens": 4096},
            mcp_servers=["gitea", "file-system", "slack"],
            tool_permissions={"allowed": ["*"], "denied": ["dangerous_tool"]},
            is_active=True,
        )
        db_session.add(agent_type)
        db_session.commit()

        retrieved = db_session.query(AgentType).filter_by(id=agent_type_id).first()

        assert retrieved.name == "Full Agent Type"
        assert retrieved.description == "A fully configured agent type"
        assert retrieved.expertise == ["python", "fastapi", "testing"]
        assert retrieved.fallback_models == ["claude-sonnet-4-20250514", "gpt-4o"]
        assert retrieved.model_params == {"temperature": 0.7, "max_tokens": 4096}
        assert retrieved.mcp_servers == ["gitea", "file-system", "slack"]
        assert retrieved.tool_permissions == {"allowed": ["*"], "denied": ["dangerous_tool"]}
        assert retrieved.is_active is True

    def test_agent_type_unique_slug_constraint(self, db_session):
        """Test that agent types cannot have duplicate slugs."""
        agent_type1 = AgentType(
            id=uuid.uuid4(),
            name="Agent One",
            slug="duplicate-agent-slug",
            personality_prompt="First agent",
            primary_model="claude-opus-4-5-20251101",
        )
        db_session.add(agent_type1)
        db_session.commit()

        agent_type2 = AgentType(
            id=uuid.uuid4(),
            name="Agent Two",
            slug="duplicate-agent-slug",  # Same slug
            personality_prompt="Second agent",
            primary_model="claude-opus-4-5-20251101",
        )
        db_session.add(agent_type2)

        with pytest.raises(IntegrityError):
            db_session.commit()

        db_session.rollback()

    def test_agent_type_timestamps(self, db_session):
        """Test that timestamps are automatically set."""
        agent_type = AgentType(
            id=uuid.uuid4(),
            name="Timestamp Agent",
            slug="timestamp-agent",
            personality_prompt="Test",
            primary_model="claude-opus-4-5-20251101",
        )
        db_session.add(agent_type)
        db_session.commit()

        retrieved = db_session.query(AgentType).filter_by(slug="timestamp-agent").first()

        assert isinstance(retrieved.created_at, datetime)
        assert isinstance(retrieved.updated_at, datetime)

    def test_agent_type_update(self, db_session):
        """Test updating agent type fields."""
        agent_type = AgentType(
            id=uuid.uuid4(),
            name="Original Agent",
            slug="original-agent",
            personality_prompt="Original prompt",
            primary_model="claude-opus-4-5-20251101",
            is_active=True,
        )
        db_session.add(agent_type)
        db_session.commit()

        original_created_at = agent_type.created_at

        # Update fields
        agent_type.name = "Updated Agent"
        agent_type.is_active = False
        agent_type.expertise = ["new", "skills"]
        db_session.commit()

        retrieved = db_session.query(AgentType).filter_by(slug="original-agent").first()

        assert retrieved.name == "Updated Agent"
        assert retrieved.is_active is False
        assert retrieved.expertise == ["new", "skills"]
        assert retrieved.created_at == original_created_at
        assert retrieved.updated_at > original_created_at

    def test_agent_type_delete(self, db_session):
        """Test deleting an agent type."""
        agent_type_id = uuid.uuid4()
        agent_type = AgentType(
            id=agent_type_id,
            name="Delete Me",
            slug="delete-me-agent",
            personality_prompt="Delete test",
            primary_model="claude-opus-4-5-20251101",
        )
        db_session.add(agent_type)
        db_session.commit()

        db_session.delete(agent_type)
        db_session.commit()

        deleted = db_session.query(AgentType).filter_by(id=agent_type_id).first()
        assert deleted is None

    def test_agent_type_string_representation(self, db_session):
        """Test the string representation of an agent type."""
        agent_type = AgentType(
            id=uuid.uuid4(),
            name="Repr Agent",
            slug="repr-agent",
            personality_prompt="Test",
            primary_model="claude-opus-4-5-20251101",
            is_active=True,
        )

        assert str(agent_type) == "<AgentType Repr Agent (repr-agent) active=True>"
        assert repr(agent_type) == "<AgentType Repr Agent (repr-agent) active=True>"


class TestAgentTypeJsonFields:
    """Tests for AgentType JSON fields."""

    def test_complex_expertise_list(self, db_session):
        """Test storing a list of expertise areas."""
        expertise = ["python", "fastapi", "sqlalchemy", "postgresql", "redis", "docker"]

        agent_type = AgentType(
            id=uuid.uuid4(),
            name="Expert Agent",
            slug="expert-agent",
            personality_prompt="Prompt",
            primary_model="claude-opus-4-5-20251101",
            expertise=expertise,
        )
        db_session.add(agent_type)
        db_session.commit()

        retrieved = db_session.query(AgentType).filter_by(slug="expert-agent").first()
        assert retrieved.expertise == expertise
        assert "python" in retrieved.expertise
        assert len(retrieved.expertise) == 6

    def test_complex_model_params(self, db_session):
        """Test storing complex model parameters."""
        model_params = {
            "temperature": 0.7,
            "max_tokens": 4096,
            "top_p": 0.9,
            "frequency_penalty": 0.1,
            "presence_penalty": 0.1,
            "stop_sequences": ["###", "END"],
        }

        agent_type = AgentType(
            id=uuid.uuid4(),
            name="Params Agent",
            slug="params-agent",
            personality_prompt="Prompt",
            primary_model="claude-opus-4-5-20251101",
            model_params=model_params,
        )
        db_session.add(agent_type)
        db_session.commit()

        retrieved = db_session.query(AgentType).filter_by(slug="params-agent").first()
        assert retrieved.model_params == model_params
        assert retrieved.model_params["temperature"] == 0.7
        assert retrieved.model_params["stop_sequences"] == ["###", "END"]

    def test_complex_tool_permissions(self, db_session):
        """Test storing complex tool permissions."""
        tool_permissions = {
            "allowed": ["file:read", "file:write", "git:commit"],
            "denied": ["file:delete", "system:exec"],
            "require_approval": ["git:push", "gitea:create_pr"],
            "limits": {
                "file:write": {"max_size_mb": 10},
                "git:commit": {"require_message": True},
            },
        }

        agent_type = AgentType(
            id=uuid.uuid4(),
            name="Permissions Agent",
            slug="permissions-agent",
            personality_prompt="Prompt",
            primary_model="claude-opus-4-5-20251101",
            tool_permissions=tool_permissions,
        )
        db_session.add(agent_type)
        db_session.commit()

        retrieved = db_session.query(AgentType).filter_by(slug="permissions-agent").first()
        assert retrieved.tool_permissions == tool_permissions
        assert "file:read" in retrieved.tool_permissions["allowed"]
        assert retrieved.tool_permissions["limits"]["file:write"]["max_size_mb"] == 10

    def test_empty_json_fields_default(self, db_session):
        """Test that JSON fields default to empty structures."""
        agent_type = AgentType(
            id=uuid.uuid4(),
            name="Empty JSON Agent",
            slug="empty-json-agent",
            personality_prompt="Prompt",
            primary_model="claude-opus-4-5-20251101",
        )
        db_session.add(agent_type)
        db_session.commit()

        retrieved = db_session.query(AgentType).filter_by(slug="empty-json-agent").first()
        assert retrieved.expertise == []
        assert retrieved.fallback_models == []
        assert retrieved.model_params == {}
        assert retrieved.mcp_servers == []
        assert retrieved.tool_permissions == {}


class TestAgentTypeIsActive:
    """Tests for AgentType is_active field."""

    def test_default_is_active(self, db_session):
        """Test that is_active defaults to True."""
        agent_type = AgentType(
            id=uuid.uuid4(),
            name="Default Active",
            slug="default-active",
            personality_prompt="Prompt",
            primary_model="claude-opus-4-5-20251101",
        )
        db_session.add(agent_type)
        db_session.commit()

        retrieved = db_session.query(AgentType).filter_by(slug="default-active").first()
        assert retrieved.is_active is True

    def test_deactivate_agent_type(self, db_session):
        """Test deactivating an agent type."""
        agent_type = AgentType(
            id=uuid.uuid4(),
            name="Deactivate Me",
            slug="deactivate-me",
            personality_prompt="Prompt",
            primary_model="claude-opus-4-5-20251101",
            is_active=True,
        )
        db_session.add(agent_type)
        db_session.commit()

        agent_type.is_active = False
        db_session.commit()

        retrieved = db_session.query(AgentType).filter_by(slug="deactivate-me").first()
        assert retrieved.is_active is False
