"""
Comprehensive tests for the Cultural Knowledge feature.

This test file covers:
1. CulturalKnowledge dataclass
2. CultureManager CRUD operations
3. Storage provider integration
4. Automatic culture updates (after each run)
5. Agentic culture (agent-controlled tools)
6. Manual culture management
7. Agent integration with culture features

Notice: Culture is an experimental feature and is subject to change.
"""

import asyncio
import pytest
from unittest.mock import AsyncMock, MagicMock, patch
from typing import List, Optional

# Import culture classes
from upsonic.culture import CulturalKnowledge, CultureManager
from upsonic.storage.providers import InMemoryStorage


# =============================================================================
# Test Fixtures
# =============================================================================

@pytest.fixture
def in_memory_storage():
    """Create a fresh in-memory storage for testing."""
    return InMemoryStorage()


@pytest.fixture
def culture_manager(in_memory_storage):
    """Create a CultureManager with in-memory storage."""
    return CultureManager(storage=in_memory_storage, debug=True)


@pytest.fixture
def sample_knowledge():
    """Create a sample CulturalKnowledge instance."""
    return CulturalKnowledge(
        id="test-id-1",
        name="Response Format Standard",
        summary="Keep responses concise and scannable",
        content="- Lead with minimal runnable snippet\n- Use numbered steps for procedures",
        categories=["communication", "ux"],
        notes=["Derived from user feedback"],
    )


@pytest.fixture
def sample_knowledge_list():
    """Create multiple CulturalKnowledge instances."""
    return [
        CulturalKnowledge(
            id="k1",
            name="Communication Style",
            summary="Be direct and professional",
            content="Always use clear, concise language",
            categories=["communication"],
        ),
        CulturalKnowledge(
            id="k2",
            name="Error Handling",
            summary="Always explain errors clearly",
            content="Provide actionable error messages",
            categories=["technical", "ux"],
        ),
        CulturalKnowledge(
            id="k3",
            name="Code Standards",
            summary="Follow PEP8 for Python",
            content="Use type hints and docstrings",
            categories=["technical", "code"],
        ),
    ]


# =============================================================================
# CulturalKnowledge Dataclass Tests
# =============================================================================

class TestCulturalKnowledge:
    """Tests for CulturalKnowledge dataclass."""
    
    def test_create_with_minimal_fields(self):
        """Test creating knowledge with minimal required fields."""
        # CulturalKnowledge requires name to be a non-empty string
        knowledge = CulturalKnowledge(name="Test")
        
        # ID is auto-generated by CultureManager.add_cultural_knowledge, not in __post_init__
        # So when creating directly, ID can be None
        assert knowledge.created_at is not None
        assert knowledge.updated_at is not None
        assert knowledge.name == "Test"
        assert knowledge.content is None
    
    def test_create_with_all_fields(self, sample_knowledge):
        """Test creating knowledge with all fields."""
        assert sample_knowledge.id == "test-id-1"
        assert sample_knowledge.name == "Response Format Standard"
        assert sample_knowledge.summary == "Keep responses concise and scannable"
        assert "Lead with minimal" in sample_knowledge.content
        assert "communication" in sample_knowledge.categories
        assert "ux" in sample_knowledge.categories
        assert len(sample_knowledge.notes) == 1
    
    def test_to_dict(self, sample_knowledge):
        """Test converting knowledge to dictionary."""
        data = sample_knowledge.to_dict()
        
        assert isinstance(data, dict)
        assert data["id"] == "test-id-1"
        assert data["name"] == "Response Format Standard"
        assert data["categories"] == ["communication", "ux"]
        assert "created_at" in data
        assert "updated_at" in data
    
    def test_from_dict(self, sample_knowledge):
        """Test creating knowledge from dictionary."""
        data = sample_knowledge.to_dict()
        restored = CulturalKnowledge.from_dict(data)
        
        assert restored.id == sample_knowledge.id
        assert restored.name == sample_knowledge.name
        assert restored.summary == sample_knowledge.summary
        assert restored.content == sample_knowledge.content
        assert restored.categories == sample_knowledge.categories
    
    def test_bump_updated_at(self, sample_knowledge):
        """Test updating the updated_at timestamp."""
        original_updated_at = sample_knowledge.updated_at
        
        # Small delay to ensure timestamp changes
        import time
        time.sleep(0.01)
        
        sample_knowledge.bump_updated_at()
        
        assert sample_knowledge.updated_at >= original_updated_at
    
    def test_preview_truncates_content(self):
        """Test that preview truncates long content."""
        long_content = "A" * 500
        knowledge = CulturalKnowledge(
            name="Long Content",
            content=long_content,
        )
        
        preview = knowledge.preview()
        
        assert isinstance(preview, dict)
        assert "name" in preview
        # Content should be truncated in preview
        if preview.get("content"):
            assert len(preview["content"]) <= 200 + 3  # +3 for "..."
    
    def test_auto_generated_id_by_manager(self):
        """Test that ID is auto-generated by CultureManager if not provided."""
        storage = InMemoryStorage()
        manager = CultureManager(storage=storage)
        
        knowledge = CulturalKnowledge(name="Test", id=None)
        
        # ID should be None before adding to manager
        assert knowledge.id is None
        
        # Manager generates ID when adding
        generated_id = manager.add_cultural_knowledge(knowledge)
        
        assert generated_id is not None
        assert len(generated_id) > 0
    
    def test_auto_generated_timestamps(self):
        """Test that timestamps are auto-generated."""
        knowledge = CulturalKnowledge(name="Test")
        
        assert knowledge.created_at is not None
        assert knowledge.updated_at is not None
        assert isinstance(knowledge.created_at, int)
        assert isinstance(knowledge.updated_at, int)


# =============================================================================
# CultureManager CRUD Tests
# =============================================================================

class TestCultureManagerCRUD:
    """Tests for CultureManager CRUD operations."""
    
    def test_add_cultural_knowledge(self, culture_manager, sample_knowledge):
        """Test adding cultural knowledge."""
        knowledge_id = culture_manager.add_cultural_knowledge(sample_knowledge)
        
        assert knowledge_id == sample_knowledge.id
        
        # Verify it was stored
        retrieved = culture_manager.get_knowledge(knowledge_id)
        assert retrieved is not None
        assert retrieved.name == sample_knowledge.name
    
    def test_add_knowledge_auto_generates_id(self, culture_manager):
        """Test that adding knowledge without ID generates one."""
        knowledge = CulturalKnowledge(
            id=None,  # Explicitly None
            name="Test Knowledge",
            content="Some content",
        )
        
        knowledge_id = culture_manager.add_cultural_knowledge(knowledge)
        
        assert knowledge_id is not None
        assert len(knowledge_id) > 0
    
    def test_get_knowledge(self, culture_manager, sample_knowledge):
        """Test retrieving knowledge by ID."""
        culture_manager.add_cultural_knowledge(sample_knowledge)
        
        retrieved = culture_manager.get_knowledge(sample_knowledge.id)
        
        assert retrieved is not None
        assert retrieved.id == sample_knowledge.id
        assert retrieved.name == sample_knowledge.name
    
    def test_get_nonexistent_knowledge(self, culture_manager):
        """Test retrieving non-existent knowledge returns None."""
        retrieved = culture_manager.get_knowledge("nonexistent-id")
        
        assert retrieved is None
    
    def test_get_all_knowledge(self, culture_manager, sample_knowledge_list):
        """Test retrieving all knowledge."""
        for knowledge in sample_knowledge_list:
            culture_manager.add_cultural_knowledge(knowledge)
        
        all_knowledge = culture_manager.get_all_knowledge()
        
        assert len(all_knowledge) == 3
    
    def test_get_all_knowledge_with_name_filter(self, culture_manager, sample_knowledge_list):
        """Test filtering knowledge by name."""
        for knowledge in sample_knowledge_list:
            culture_manager.add_cultural_knowledge(knowledge)
        
        # Filter by partial name match
        filtered = culture_manager.get_all_knowledge(name="Style")
        
        assert len(filtered) >= 1
        assert any("Style" in k.name for k in filtered)
    
    def test_delete_cultural_knowledge(self, culture_manager, sample_knowledge):
        """Test deleting knowledge."""
        culture_manager.add_cultural_knowledge(sample_knowledge)
        
        # Verify it exists
        assert culture_manager.get_knowledge(sample_knowledge.id) is not None
        
        # Delete it
        culture_manager.delete_cultural_knowledge(sample_knowledge.id)
        
        # Verify it's gone
        assert culture_manager.get_knowledge(sample_knowledge.id) is None
    
    def test_clear_all_knowledge(self, culture_manager, sample_knowledge_list):
        """Test clearing all knowledge."""
        for knowledge in sample_knowledge_list:
            culture_manager.add_cultural_knowledge(knowledge)
        
        assert len(culture_manager.get_all_knowledge()) == 3
        
        culture_manager.clear_all_knowledge()
        
        assert len(culture_manager.get_all_knowledge()) == 0


# =============================================================================
# CultureManager Async CRUD Tests
# =============================================================================

class TestCultureManagerAsyncCRUD:
    """Tests for CultureManager async CRUD operations."""
    
    @pytest.mark.asyncio
    async def test_aadd_cultural_knowledge(self, culture_manager, sample_knowledge):
        """Test async adding cultural knowledge."""
        knowledge_id = await culture_manager.aadd_cultural_knowledge(sample_knowledge)
        
        assert knowledge_id == sample_knowledge.id
    
    @pytest.mark.asyncio
    async def test_aget_knowledge(self, culture_manager, sample_knowledge):
        """Test async retrieving knowledge."""
        await culture_manager.aadd_cultural_knowledge(sample_knowledge)
        
        retrieved = await culture_manager.aget_knowledge(sample_knowledge.id)
        
        assert retrieved is not None
        assert retrieved.id == sample_knowledge.id
    
    @pytest.mark.asyncio
    async def test_aget_all_knowledge(self, culture_manager, sample_knowledge_list):
        """Test async retrieving all knowledge."""
        for knowledge in sample_knowledge_list:
            await culture_manager.aadd_cultural_knowledge(knowledge)
        
        all_knowledge = await culture_manager.aget_all_knowledge()
        
        assert len(all_knowledge) == 3
    
    @pytest.mark.asyncio
    async def test_adelete_cultural_knowledge(self, culture_manager, sample_knowledge):
        """Test async deleting knowledge."""
        await culture_manager.aadd_cultural_knowledge(sample_knowledge)
        await culture_manager.adelete_cultural_knowledge(sample_knowledge.id)
        
        retrieved = await culture_manager.aget_knowledge(sample_knowledge.id)
        assert retrieved is None
    
    @pytest.mark.asyncio
    async def test_aclear_all_knowledge(self, culture_manager, sample_knowledge_list):
        """Test async clearing all knowledge."""
        for knowledge in sample_knowledge_list:
            await culture_manager.aadd_cultural_knowledge(knowledge)
        
        await culture_manager.aclear_all_knowledge()
        
        all_knowledge = await culture_manager.aget_all_knowledge()
        assert len(all_knowledge) == 0


# =============================================================================
# CultureManager Tool Generation Tests
# =============================================================================

class TestCultureManagerTools:
    """Tests for CultureManager tool generation."""
    
    def test_get_culture_tools_default(self, culture_manager):
        """Test getting default culture tools (add + update only)."""
        tools = culture_manager.get_culture_tools()
        
        # By default, add and update are enabled, delete and clear are disabled
        assert len(tools) == 2  # add + update
        
        tool_names = [t.__name__ for t in tools]
        assert "add_cultural_knowledge" in tool_names
        assert "update_cultural_knowledge" in tool_names
    
    def test_get_culture_tools_with_delete(self, in_memory_storage):
        """Test getting culture tools with delete enabled."""
        manager = CultureManager(
            storage=in_memory_storage,
            delete_knowledge=True,
        )
        
        tools = manager.get_culture_tools()
        
        assert len(tools) == 3  # add + update + delete
        tool_names = [t.__name__ for t in tools]
        assert "delete_cultural_knowledge" in tool_names
    
    def test_get_culture_tools_all(self, in_memory_storage):
        """Test getting all culture tools."""
        manager = CultureManager(
            storage=in_memory_storage,
            add_knowledge=True,
            update_knowledge=True,
            delete_knowledge=True,
            clear_knowledge=True,
        )
        
        tools = manager.get_culture_tools()
        
        assert len(tools) == 4  # all tools
        tool_names = [t.__name__ for t in tools]
        assert "add_cultural_knowledge" in tool_names
        assert "update_cultural_knowledge" in tool_names
        assert "delete_cultural_knowledge" in tool_names
        assert "clear_cultural_knowledge" in tool_names
    
    def test_tool_add_knowledge_executes(self, culture_manager):
        """Test that the add tool actually works."""
        tools = culture_manager.get_culture_tools()
        add_tool = next(t for t in tools if t.__name__ == "add_cultural_knowledge")
        
        result = add_tool(
            name="Test Knowledge",
            summary="Test summary",
            content="Test content",
            categories=["test"],
        )
        
        assert "Successfully added" in result
        assert culture_manager.knowledge_updated is True
    
    def test_tool_update_knowledge_executes(self, culture_manager, sample_knowledge):
        """Test that the update tool actually works."""
        culture_manager.add_cultural_knowledge(sample_knowledge)
        
        tools = culture_manager.get_culture_tools()
        update_tool = next(t for t in tools if t.__name__ == "update_cultural_knowledge")
        
        result = update_tool(
            knowledge_id=sample_knowledge.id,
            name="Updated Name",
        )
        
        assert "Successfully updated" in result
        assert culture_manager.knowledge_updated is True
        
        # Verify the update
        updated = culture_manager.get_knowledge(sample_knowledge.id)
        assert updated.name == "Updated Name"


# =============================================================================
# CultureManager Context Building Tests
# =============================================================================

class TestCultureManagerContext:
    """Tests for CultureManager context building."""
    
    def test_get_culture_context_empty(self, culture_manager):
        """Test getting culture context with no knowledge."""
        context = culture_manager.get_culture_context()
        
        # Should return empty or minimal context
        assert context == "" or "no cultural knowledge" in context.lower()
    
    def test_get_culture_context_with_knowledge(self, culture_manager, sample_knowledge_list):
        """Test getting culture context with knowledge."""
        for knowledge in sample_knowledge_list:
            culture_manager.add_cultural_knowledge(knowledge)
        
        context = culture_manager.get_culture_context()
        
        assert len(context) > 0
        assert "Cultural Knowledge" in context
        # Should contain knowledge names
        assert "Communication Style" in context
        assert "Error Handling" in context
    
    @pytest.mark.asyncio
    async def test_aget_culture_context(self, culture_manager, sample_knowledge_list):
        """Test async getting culture context."""
        for knowledge in sample_knowledge_list:
            await culture_manager.aadd_cultural_knowledge(knowledge)
        
        context = await culture_manager.aget_culture_context()
        
        assert len(context) > 0
        assert "Cultural Knowledge" in context


# =============================================================================
# CultureManager System Message Tests
# =============================================================================

class TestCultureManagerSystemMessage:
    """Tests for CultureManager system message generation."""
    
    def test_get_system_message_structure(self, culture_manager):
        """Test that system message has correct structure."""
        system_msg = culture_manager.get_system_message(
            existing_knowledge=[],
            enable_add_knowledge=True,
            enable_update_knowledge=True,
        )
        
        assert "Cultural Knowledge Manager" in system_msg
        assert "Your Role" in system_msg
        assert "Criteria" in system_msg or "knowledge_to_capture" in system_msg
    
    def test_get_system_message_includes_existing_knowledge(self, culture_manager, sample_knowledge):
        """Test that system message includes existing knowledge."""
        preview = sample_knowledge.preview()
        
        system_msg = culture_manager.get_system_message(
            existing_knowledge=[preview],
            enable_add_knowledge=True,
            enable_update_knowledge=True,
        )
        
        # The system message includes "Existing Knowledge" section with the knowledge info
        assert "Existing Knowledge" in system_msg
        assert sample_knowledge.name in system_msg
    
    def test_get_system_message_tool_instructions(self, culture_manager):
        """Test that system message includes tool instructions."""
        system_msg = culture_manager.get_system_message(
            existing_knowledge=[],
            enable_add_knowledge=True,
            enable_update_knowledge=True,
            enable_delete_knowledge=True,
        )
        
        # Should mention available tools
        assert "add_cultural_knowledge" in system_msg or "add" in system_msg.lower()


# =============================================================================
# Storage Provider Integration Tests
# =============================================================================

class TestStorageProviderIntegration:
    """Tests for culture with different storage providers."""
    
    def test_in_memory_storage_culture(self, sample_knowledge):
        """Test culture with InMemoryStorage."""
        storage = InMemoryStorage()
        manager = CultureManager(storage=storage)
        
        # CRUD operations
        manager.add_cultural_knowledge(sample_knowledge)
        retrieved = manager.get_knowledge(sample_knowledge.id)
        
        assert retrieved is not None
        assert retrieved.name == sample_knowledge.name
    
    @pytest.mark.asyncio
    async def test_in_memory_storage_culture_async(self, sample_knowledge):
        """Test async culture with InMemoryStorage."""
        storage = InMemoryStorage()
        manager = CultureManager(storage=storage)
        
        await manager.aadd_cultural_knowledge(sample_knowledge)
        retrieved = await manager.aget_knowledge(sample_knowledge.id)
        
        assert retrieved is not None
        assert retrieved.name == sample_knowledge.name


# =============================================================================
# Agent Integration Tests
# =============================================================================

class TestAgentCultureIntegration:
    """Tests for Agent integration with culture features."""
    
    def test_agent_auto_creates_culture_manager(self):
        """Test that Agent auto-creates CultureManager when culture is enabled."""
        from upsonic.agent import Agent
        
        # Create agent with culture enabled but no manager
        agent = Agent(
            model="openai/gpt-4o-mini",
            add_culture_to_context=True,
        )
        
        # CultureManager should be auto-created
        assert agent.culture_manager is not None
        assert isinstance(agent.culture_manager, CultureManager)
    
    def test_agent_with_update_cultural_knowledge(self):
        """Test Agent with update_cultural_knowledge enabled."""
        from upsonic.agent import Agent
        
        agent = Agent(
            model="openai/gpt-4o-mini",
            update_cultural_knowledge=True,
        )
        
        assert agent.culture_manager is not None
        assert agent.update_cultural_knowledge is True
    
    def test_agent_with_provided_culture_manager(self, culture_manager):
        """Test Agent with provided CultureManager."""
        from upsonic.agent import Agent
        
        agent = Agent(
            model="openai/gpt-4o-mini",
            culture_manager=culture_manager,
            add_culture_to_context=True,
        )
        
        assert agent.culture_manager is culture_manager
    
    def test_agent_agentic_culture_adds_tools(self, culture_manager):
        """Test that enable_agentic_culture adds culture tools to agent."""
        from upsonic.agent import Agent
        
        initial_tools_count = 0
        
        agent = Agent(
            model="openai/gpt-4o-mini",
            culture_manager=culture_manager,
            enable_agentic_culture=True,
        )
        
        # Agent should have culture tools
        tool_names = [getattr(t, '__name__', str(t)) for t in agent.tools]
        assert "add_cultural_knowledge" in tool_names or any("culture" in name.lower() for name in tool_names)
    
    def test_agent_uses_memory_storage(self):
        """Test that Agent uses memory's storage for CultureManager."""
        from upsonic.agent import Agent
        from upsonic.storage.memory import Memory
        
        storage = InMemoryStorage()
        memory = Memory(
            storage=storage,
            session_id="test-session",
            full_session_memory=True,
        )
        
        agent = Agent(
            model="openai/gpt-4o-mini",
            memory=memory,
            add_culture_to_context=True,
        )
        
        # CultureManager should use the same storage as memory
        assert agent.culture_manager.storage is storage
    
    def test_agent_no_culture_manager_when_disabled(self):
        """Test that Agent has no CultureManager when culture is disabled."""
        from upsonic.agent import Agent
        
        agent = Agent(
            model="openai/gpt-4o-mini",
            add_culture_to_context=False,
            update_cultural_knowledge=False,
            enable_agentic_culture=False,
        )
        
        assert agent.culture_manager is None


# =============================================================================
# Manual Culture Management Tests
# =============================================================================

class TestManualCultureManagement:
    """Tests for manual culture management workflow."""
    
    def test_manual_add_knowledge(self, culture_manager):
        """Test manually adding cultural knowledge."""
        # Create knowledge directly
        knowledge = CulturalKnowledge(
            name="API Design Standards",
            summary="Follow REST best practices",
            content="Use proper HTTP methods and status codes",
            categories=["technical", "api"],
        )
        
        # Add it manually
        knowledge_id = culture_manager.add_cultural_knowledge(knowledge)
        
        # Verify
        retrieved = culture_manager.get_knowledge(knowledge_id)
        assert retrieved.name == "API Design Standards"
    
    def test_manual_update_knowledge(self, culture_manager, sample_knowledge):
        """Test manually updating cultural knowledge."""
        culture_manager.add_cultural_knowledge(sample_knowledge)
        
        # Get, modify, and re-add
        knowledge = culture_manager.get_knowledge(sample_knowledge.id)
        knowledge.content = "Updated content"
        
        culture_manager.add_cultural_knowledge(knowledge)
        
        # Verify update
        updated = culture_manager.get_knowledge(sample_knowledge.id)
        assert updated.content == "Updated content"
    
    def test_manual_list_and_preview(self, culture_manager, sample_knowledge_list):
        """Test manually listing and previewing knowledge."""
        for knowledge in sample_knowledge_list:
            culture_manager.add_cultural_knowledge(knowledge)
        
        all_knowledge = culture_manager.get_all_knowledge()
        
        # Preview each
        previews = [k.preview() for k in all_knowledge]
        
        assert len(previews) == 3
        for preview in previews:
            assert "id" in preview
            assert "name" in preview


# =============================================================================
# Culture Debug Mode Tests
# =============================================================================

class TestCultureDebugMode:
    """Tests for culture debug mode."""
    
    def test_culture_manager_debug_flag(self, in_memory_storage):
        """Test that debug flag is properly set."""
        manager = CultureManager(storage=in_memory_storage, debug=True)
        
        assert manager.debug is True
    
    def test_culture_manager_debug_default(self, in_memory_storage):
        """Test that debug is False by default."""
        manager = CultureManager(storage=in_memory_storage)
        
        assert manager.debug is False


# =============================================================================
# CultureUpdateEvent Tests
# =============================================================================

class TestCultureUpdateEvent:
    """Tests for CultureUpdateEvent."""
    
    def test_event_creation(self):
        """Test creating CultureUpdateEvent."""
        from upsonic.run.events.events import CultureUpdateEvent
        
        event = CultureUpdateEvent(
            culture_enabled=True,
            extraction_triggered=True,
            knowledge_updated=True,
        )
        
        assert event.culture_enabled is True
        assert event.extraction_triggered is True
        assert event.knowledge_updated is True
        assert event.event_kind == "culture_update"
    
    def test_event_defaults(self):
        """Test CultureUpdateEvent default values."""
        from upsonic.run.events.events import CultureUpdateEvent
        
        event = CultureUpdateEvent()
        
        assert event.culture_enabled is False
        assert event.extraction_triggered is False
        assert event.knowledge_updated is False


# =============================================================================
# Integration Test: Full Culture Workflow
# =============================================================================

class TestFullCultureWorkflow:
    """Integration tests for complete culture workflows."""
    
    def test_workflow_manual_then_context(self, in_memory_storage):
        """Test workflow: manually add knowledge, then use in context."""
        manager = CultureManager(storage=in_memory_storage, debug=True)
        
        # Step 1: Manually add cultural knowledge
        knowledge = CulturalKnowledge(
            name="Professional Tone",
            content="Always maintain a professional and helpful tone.",
            categories=["communication"],
        )
        manager.add_cultural_knowledge(knowledge)
        
        # Step 2: Get culture context for agent
        context = manager.get_culture_context()
        
        # Verify knowledge is in context
        assert "Professional Tone" in context
        assert "communication" in context.lower() or len(context) > 0
    
    @pytest.mark.asyncio
    async def test_workflow_async_crud(self, in_memory_storage):
        """Test async workflow: add, list, update, delete."""
        manager = CultureManager(storage=in_memory_storage)
        
        # Add
        knowledge = CulturalKnowledge(
            name="Test Knowledge",
            content="Initial content",
        )
        kid = await manager.aadd_cultural_knowledge(knowledge)
        
        # List
        all_k = await manager.aget_all_knowledge()
        assert len(all_k) == 1
        
        # Update
        knowledge.content = "Updated content"
        await manager.aadd_cultural_knowledge(knowledge)
        
        retrieved = await manager.aget_knowledge(kid)
        assert retrieved.content == "Updated content"
        
        # Delete
        await manager.adelete_cultural_knowledge(kid)
        
        final = await manager.aget_all_knowledge()
        assert len(final) == 0


# =============================================================================
# Edge Cases and Error Handling
# =============================================================================

class TestCultureEdgeCases:
    """Tests for edge cases and error handling."""
    
    def test_empty_knowledge_name_raises_error(self, culture_manager):
        """Test that empty name raises ValueError."""
        import pytest
        
        with pytest.raises(ValueError, match="name must be a non-empty string"):
            CulturalKnowledge(
                name="",  # Empty name raises error
                content="Some content",
            )
    
    def test_none_values_in_knowledge(self, culture_manager):
        """Test adding knowledge with None values."""
        knowledge = CulturalKnowledge(
            name=None,
            content=None,
            summary=None,
        )
        
        knowledge_id = culture_manager.add_cultural_knowledge(knowledge)
        
        retrieved = culture_manager.get_knowledge(knowledge_id)
        assert retrieved is not None
    
    def test_special_characters_in_content(self, culture_manager):
        """Test knowledge with special characters."""
        knowledge = CulturalKnowledge(
            name="Special Chars Test",
            content="Test with émojis 🎉 and spëcial çharacters!",
            notes=["Note with 日本語 characters"],
        )
        
        knowledge_id = culture_manager.add_cultural_knowledge(knowledge)
        
        retrieved = culture_manager.get_knowledge(knowledge_id)
        assert "émojis" in retrieved.content
        assert "🎉" in retrieved.content
        assert "日本語" in retrieved.notes[0]
    
    def test_large_content(self, culture_manager):
        """Test knowledge with very large content."""
        large_content = "A" * 10000  # 10KB of content
        
        knowledge = CulturalKnowledge(
            name="Large Content",
            content=large_content,
        )
        
        knowledge_id = culture_manager.add_cultural_knowledge(knowledge)
        
        retrieved = culture_manager.get_knowledge(knowledge_id)
        assert len(retrieved.content) == 10000
    
    def test_delete_nonexistent_knowledge(self, culture_manager):
        """Test deleting non-existent knowledge doesn't raise."""
        # Should not raise an exception
        culture_manager.delete_cultural_knowledge("nonexistent-id")
    
    def test_clear_empty_storage(self, culture_manager):
        """Test clearing already empty storage."""
        # Should not raise
        culture_manager.clear_all_knowledge()
        
        all_k = culture_manager.get_all_knowledge()
        assert len(all_k) == 0
