# tests/schemas/syndarix/test_agent_type_schemas.py
"""
Tests for AgentType schema validation.
"""

import pytest
from pydantic import ValidationError

from app.schemas.syndarix import (
    AgentTypeCreate,
    AgentTypeUpdate,
)


class TestAgentTypeCreateValidation:
    """Tests for AgentTypeCreate schema validation."""

    def test_valid_agent_type_create(self, valid_agent_type_data):
        """Test creating agent type with valid data."""
        agent_type = AgentTypeCreate(**valid_agent_type_data)

        assert agent_type.name == "Backend Engineer"
        assert agent_type.slug == "backend-engineer"
        assert agent_type.personality_prompt == "You are an expert backend engineer."
        assert agent_type.primary_model == "claude-opus-4-5-20251101"

    def test_agent_type_create_defaults(self, valid_agent_type_data):
        """Test that defaults are applied correctly."""
        agent_type = AgentTypeCreate(**valid_agent_type_data)

        assert agent_type.expertise == []
        assert agent_type.fallback_models == []
        assert agent_type.model_params == {}
        assert agent_type.mcp_servers == []
        assert agent_type.tool_permissions == {}
        assert agent_type.is_active is True

    def test_agent_type_create_with_all_fields(self, valid_agent_type_data):
        """Test creating agent type with all optional fields."""
        agent_type = AgentTypeCreate(
            **valid_agent_type_data,
            description="Detailed description",
            expertise=["python", "fastapi"],
            fallback_models=["claude-sonnet-4-20250514"],
            model_params={"temperature": 0.7},
            mcp_servers=["gitea", "slack"],
            tool_permissions={"allowed": ["*"]},
            is_active=True,
        )

        assert agent_type.description == "Detailed description"
        assert agent_type.expertise == ["python", "fastapi"]
        assert agent_type.fallback_models == ["claude-sonnet-4-20250514"]

    def test_agent_type_create_name_empty_fails(self):
        """Test that empty name raises ValidationError."""
        with pytest.raises(ValidationError) as exc_info:
            AgentTypeCreate(
                name="",
                slug="valid-slug",
                personality_prompt="Test prompt",
                primary_model="claude-opus-4-5-20251101",
            )

        errors = exc_info.value.errors()
        assert any("name" in str(e) for e in errors)

    def test_agent_type_create_name_stripped(self):
        """Test that name is stripped of whitespace."""
        agent_type = AgentTypeCreate(
            name="  Padded Name  ",
            slug="padded-slug",
            personality_prompt="Test",
            primary_model="claude-opus-4-5-20251101",
        )

        assert agent_type.name == "Padded Name"

    def test_agent_type_create_personality_prompt_required(self):
        """Test that personality_prompt is required."""
        with pytest.raises(ValidationError) as exc_info:
            AgentTypeCreate(
                name="Test Agent",
                slug="test-agent",
                primary_model="claude-opus-4-5-20251101",
            )

        errors = exc_info.value.errors()
        assert any("personality_prompt" in str(e).lower() for e in errors)

    def test_agent_type_create_primary_model_required(self):
        """Test that primary_model is required."""
        with pytest.raises(ValidationError) as exc_info:
            AgentTypeCreate(
                name="Test Agent",
                slug="test-agent",
                personality_prompt="Test prompt",
            )

        errors = exc_info.value.errors()
        assert any("primary_model" in str(e).lower() for e in errors)


class TestAgentTypeSlugValidation:
    """Tests for AgentType slug validation."""

    def test_valid_slugs(self):
        """Test various valid slug formats."""
        valid_slugs = [
            "simple",
            "with-hyphens",
            "has123numbers",
        ]

        for slug in valid_slugs:
            agent_type = AgentTypeCreate(
                name="Test Agent",
                slug=slug,
                personality_prompt="Test",
                primary_model="claude-opus-4-5-20251101",
            )
            assert agent_type.slug == slug

    def test_invalid_slug_uppercase(self):
        """Test that uppercase letters in slug raise ValidationError."""
        with pytest.raises(ValidationError):
            AgentTypeCreate(
                name="Test Agent",
                slug="Invalid-Uppercase",
                personality_prompt="Test",
                primary_model="claude-opus-4-5-20251101",
            )

    def test_invalid_slug_special_chars(self):
        """Test that special characters raise ValidationError."""
        with pytest.raises(ValidationError):
            AgentTypeCreate(
                name="Test Agent",
                slug="has_underscore",
                personality_prompt="Test",
                primary_model="claude-opus-4-5-20251101",
            )


class TestAgentTypeExpertiseValidation:
    """Tests for AgentType expertise validation."""

    def test_expertise_normalized_lowercase(self):
        """Test that expertise is normalized to lowercase."""
        agent_type = AgentTypeCreate(
            name="Test Agent",
            slug="test-agent",
            personality_prompt="Test",
            primary_model="claude-opus-4-5-20251101",
            expertise=["Python", "FastAPI", "PostgreSQL"],
        )

        assert agent_type.expertise == ["python", "fastapi", "postgresql"]

    def test_expertise_stripped(self):
        """Test that expertise items are stripped."""
        agent_type = AgentTypeCreate(
            name="Test Agent",
            slug="test-agent",
            personality_prompt="Test",
            primary_model="claude-opus-4-5-20251101",
            expertise=["  python  ", "  fastapi  "],
        )

        assert agent_type.expertise == ["python", "fastapi"]

    def test_expertise_empty_strings_removed(self):
        """Test that empty expertise strings are removed."""
        agent_type = AgentTypeCreate(
            name="Test Agent",
            slug="test-agent",
            personality_prompt="Test",
            primary_model="claude-opus-4-5-20251101",
            expertise=["python", "", "  ", "fastapi"],
        )

        assert agent_type.expertise == ["python", "fastapi"]


class TestAgentTypeMcpServersValidation:
    """Tests for AgentType MCP servers validation."""

    def test_mcp_servers_stripped(self):
        """Test that MCP server names are stripped."""
        agent_type = AgentTypeCreate(
            name="Test Agent",
            slug="test-agent",
            personality_prompt="Test",
            primary_model="claude-opus-4-5-20251101",
            mcp_servers=["  gitea  ", "  slack  "],
        )

        assert agent_type.mcp_servers == ["gitea", "slack"]

    def test_mcp_servers_empty_strings_removed(self):
        """Test that empty MCP server strings are removed."""
        agent_type = AgentTypeCreate(
            name="Test Agent",
            slug="test-agent",
            personality_prompt="Test",
            primary_model="claude-opus-4-5-20251101",
            mcp_servers=["gitea", "", "  ", "slack"],
        )

        assert agent_type.mcp_servers == ["gitea", "slack"]


class TestAgentTypeUpdateValidation:
    """Tests for AgentTypeUpdate schema validation."""

    def test_agent_type_update_partial(self):
        """Test updating only some fields."""
        update = AgentTypeUpdate(
            name="Updated Name",
        )

        assert update.name == "Updated Name"
        assert update.slug is None
        assert update.description is None
        assert update.expertise is None

    def test_agent_type_update_all_fields(self):
        """Test updating all fields."""
        update = AgentTypeUpdate(
            name="Updated Name",
            slug="updated-slug",
            description="Updated description",
            expertise=["new-skill"],
            personality_prompt="Updated prompt",
            primary_model="new-model",
            fallback_models=["fallback-1"],
            model_params={"temp": 0.5},
            mcp_servers=["server-1"],
            tool_permissions={"key": "value"},
            is_active=False,
        )

        assert update.name == "Updated Name"
        assert update.slug == "updated-slug"
        assert update.is_active is False

    def test_agent_type_update_empty_name_fails(self):
        """Test that empty name in update raises ValidationError."""
        with pytest.raises(ValidationError) as exc_info:
            AgentTypeUpdate(name="")

        errors = exc_info.value.errors()
        assert any("name" in str(e) for e in errors)

    def test_agent_type_update_slug_validation(self):
        """Test that slug validation applies to updates."""
        with pytest.raises(ValidationError):
            AgentTypeUpdate(slug="Invalid-Slug")

    def test_agent_type_update_expertise_normalized(self):
        """Test that expertise is normalized in updates."""
        update = AgentTypeUpdate(
            expertise=["Python", "FastAPI"],
        )

        assert update.expertise == ["python", "fastapi"]


class TestAgentTypeJsonFields:
    """Tests for AgentType JSON field validation."""

    def test_model_params_complex(self):
        """Test complex model_params structure."""
        params = {
            "temperature": 0.7,
            "max_tokens": 4096,
            "top_p": 0.9,
            "stop_sequences": ["###"],
        }
        agent_type = AgentTypeCreate(
            name="Test Agent",
            slug="test-agent",
            personality_prompt="Test",
            primary_model="claude-opus-4-5-20251101",
            model_params=params,
        )

        assert agent_type.model_params == params

    def test_tool_permissions_complex(self):
        """Test complex tool_permissions structure."""
        permissions = {
            "allowed": ["file:read", "git:commit"],
            "denied": ["file:delete"],
            "require_approval": ["git:push"],
        }
        agent_type = AgentTypeCreate(
            name="Test Agent",
            slug="test-agent",
            personality_prompt="Test",
            primary_model="claude-opus-4-5-20251101",
            tool_permissions=permissions,
        )

        assert agent_type.tool_permissions == permissions

    def test_fallback_models_list(self):
        """Test fallback_models as a list."""
        models = ["claude-sonnet-4-20250514", "gpt-4o", "mistral-large"]
        agent_type = AgentTypeCreate(
            name="Test Agent",
            slug="test-agent",
            personality_prompt="Test",
            primary_model="claude-opus-4-5-20251101",
            fallback_models=models,
        )

        assert agent_type.fallback_models == models
