# tests/schemas/syndarix/test_agent_instance_schemas.py
"""
Tests for AgentInstance schema validation.
"""

from decimal import Decimal

import pytest
from pydantic import ValidationError

from app.schemas.syndarix import (
    AgentInstanceCreate,
    AgentInstanceUpdate,
    AgentStatus,
)


class TestAgentInstanceCreateValidation:
    """Tests for AgentInstanceCreate schema validation."""

    def test_valid_agent_instance_create(self, valid_agent_instance_data):
        """Test creating agent instance with valid data."""
        instance = AgentInstanceCreate(**valid_agent_instance_data)

        assert instance.agent_type_id is not None
        assert instance.project_id is not None

    def test_agent_instance_create_defaults(self, valid_agent_instance_data):
        """Test that defaults are applied correctly."""
        instance = AgentInstanceCreate(**valid_agent_instance_data)

        assert instance.status == AgentStatus.IDLE
        assert instance.current_task is None
        assert instance.short_term_memory == {}
        assert instance.long_term_memory_ref is None
        assert instance.session_id is None

    def test_agent_instance_create_with_all_fields(self, valid_uuid):
        """Test creating agent instance with all optional fields."""
        instance = AgentInstanceCreate(
            agent_type_id=valid_uuid,
            project_id=valid_uuid,
            name="WorkingAgent",
            status=AgentStatus.WORKING,
            current_task="Processing feature request",
            short_term_memory={"context": "working"},
            long_term_memory_ref="project-123/agent-456",
            session_id="session-abc",
        )

        assert instance.status == AgentStatus.WORKING
        assert instance.current_task == "Processing feature request"
        assert instance.short_term_memory == {"context": "working"}
        assert instance.long_term_memory_ref == "project-123/agent-456"
        assert instance.session_id == "session-abc"

    def test_agent_instance_create_agent_type_id_required(self, valid_uuid):
        """Test that agent_type_id is required."""
        with pytest.raises(ValidationError) as exc_info:
            AgentInstanceCreate(
                project_id=valid_uuid,
                name="TestAgent",
            )

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

    def test_agent_instance_create_project_id_required(self, valid_uuid):
        """Test that project_id is required."""
        with pytest.raises(ValidationError) as exc_info:
            AgentInstanceCreate(
                agent_type_id=valid_uuid,
                name="TestAgent",
            )

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

    def test_agent_instance_create_name_required(self, valid_uuid):
        """Test that name is required."""
        with pytest.raises(ValidationError) as exc_info:
            AgentInstanceCreate(
                agent_type_id=valid_uuid,
                project_id=valid_uuid,
            )

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


class TestAgentInstanceUpdateValidation:
    """Tests for AgentInstanceUpdate schema validation."""

    def test_agent_instance_update_partial(self):
        """Test updating only some fields."""
        update = AgentInstanceUpdate(
            status=AgentStatus.WORKING,
        )

        assert update.status == AgentStatus.WORKING
        assert update.current_task is None
        assert update.short_term_memory is None

    def test_agent_instance_update_all_fields(self):
        """Test updating all fields."""
        from datetime import UTC, datetime

        now = datetime.now(UTC)
        update = AgentInstanceUpdate(
            status=AgentStatus.WORKING,
            current_task="New task",
            short_term_memory={"new": "context"},
            long_term_memory_ref="new-ref",
            session_id="new-session",
            last_activity_at=now,
            tasks_completed=5,
            tokens_used=10000,
            cost_incurred=Decimal("1.5000"),
        )

        assert update.status == AgentStatus.WORKING
        assert update.current_task == "New task"
        assert update.tasks_completed == 5
        assert update.tokens_used == 10000
        assert update.cost_incurred == Decimal("1.5000")

    def test_agent_instance_update_tasks_completed_negative_fails(self):
        """Test that negative tasks_completed raises ValidationError."""
        with pytest.raises(ValidationError) as exc_info:
            AgentInstanceUpdate(tasks_completed=-1)

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

    def test_agent_instance_update_tokens_used_negative_fails(self):
        """Test that negative tokens_used raises ValidationError."""
        with pytest.raises(ValidationError) as exc_info:
            AgentInstanceUpdate(tokens_used=-1)

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

    def test_agent_instance_update_cost_incurred_negative_fails(self):
        """Test that negative cost_incurred raises ValidationError."""
        with pytest.raises(ValidationError) as exc_info:
            AgentInstanceUpdate(cost_incurred=Decimal("-0.01"))

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


class TestAgentStatusEnum:
    """Tests for AgentStatus enum validation."""

    def test_valid_agent_statuses(self, valid_uuid):
        """Test all valid agent statuses."""
        for status in AgentStatus:
            instance = AgentInstanceCreate(
                agent_type_id=valid_uuid,
                project_id=valid_uuid,
                name=f"Agent{status.value}",
                status=status,
            )
            assert instance.status == status

    def test_invalid_agent_status(self, valid_uuid):
        """Test that invalid agent status raises ValidationError."""
        with pytest.raises(ValidationError):
            AgentInstanceCreate(
                agent_type_id=valid_uuid,
                project_id=valid_uuid,
                name="TestAgent",
                status="invalid",  # type: ignore
            )


class TestAgentInstanceShortTermMemory:
    """Tests for AgentInstance short_term_memory validation."""

    def test_short_term_memory_empty_dict(self, valid_uuid):
        """Test that empty short_term_memory is valid."""
        instance = AgentInstanceCreate(
            agent_type_id=valid_uuid,
            project_id=valid_uuid,
            name="TestAgent",
            short_term_memory={},
        )
        assert instance.short_term_memory == {}

    def test_short_term_memory_complex(self, valid_uuid):
        """Test complex short_term_memory structure."""
        memory = {
            "conversation_history": [
                {"role": "user", "content": "Hello"},
                {"role": "assistant", "content": "Hi there"},
            ],
            "recent_files": ["file1.py", "file2.py"],
            "decisions": {"key": "value"},
            "context_tokens": 1024,
        }
        instance = AgentInstanceCreate(
            agent_type_id=valid_uuid,
            project_id=valid_uuid,
            name="MemoryAgent",
            short_term_memory=memory,
        )
        assert instance.short_term_memory == memory


class TestAgentInstanceStringFields:
    """Tests for AgentInstance string field validation."""

    def test_long_term_memory_ref_max_length(self, valid_uuid):
        """Test long_term_memory_ref max length."""
        long_ref = "a" * 500  # Max length is 500

        instance = AgentInstanceCreate(
            agent_type_id=valid_uuid,
            project_id=valid_uuid,
            name="TestAgent",
            long_term_memory_ref=long_ref,
        )
        assert instance.long_term_memory_ref == long_ref

    def test_long_term_memory_ref_too_long(self, valid_uuid):
        """Test that too long long_term_memory_ref raises ValidationError."""
        too_long = "a" * 501

        with pytest.raises(ValidationError) as exc_info:
            AgentInstanceCreate(
                agent_type_id=valid_uuid,
                project_id=valid_uuid,
                name="TestAgent",
                long_term_memory_ref=too_long,
            )

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

    def test_session_id_max_length(self, valid_uuid):
        """Test session_id max length."""
        long_session = "a" * 255  # Max length is 255

        instance = AgentInstanceCreate(
            agent_type_id=valid_uuid,
            project_id=valid_uuid,
            name="TestAgent",
            session_id=long_session,
        )
        assert instance.session_id == long_session

    def test_session_id_too_long(self, valid_uuid):
        """Test that too long session_id raises ValidationError."""
        too_long = "a" * 256

        with pytest.raises(ValidationError) as exc_info:
            AgentInstanceCreate(
                agent_type_id=valid_uuid,
                project_id=valid_uuid,
                name="TestAgent",
                session_id=too_long,
            )

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