"""
Integration tests for MCP Memory Service tool consolidation.

These tests verify the full pipeline from tool call to response.
"""

import pytest
import json
from mcp.types import TextContent


# Import server implementation
try:
    from mcp_memory_service.server_impl import MemoryServer
except ImportError:
    # Fallback for different import paths
    from mcp_memory_service.server.server_impl import MemoryServer


@pytest.fixture
async def server(temp_db_path):
    """Create and initialize server for testing."""
    # Override storage path with temp directory
    import os
    os.environ["MCP_MEMORY_SQLITE_PATH"] = str(temp_db_path / "test_integration.db")

    server = MemoryServer()
    await server.initialize()
    yield server
    # Cleanup happens via temp_db_path fixture


class TestToolDiscovery:
    """Test that only new tools are exposed."""

    @pytest.mark.asyncio
    async def test_only_12_tools_exposed(self, server):
        """Verify exactly 12 new tools are listed."""
        result = await server.list_tools()
        tools = result.tools

        assert len(tools) == 12, f"Expected 12 tools, got {len(tools)}: {[t.name for t in tools]}"

        expected_names = {
            "memory_store",
            "memory_search",
            "memory_list",
            "memory_delete",
            "memory_update",
            "memory_health",
            "memory_stats",
            "memory_consolidate",
            "memory_cleanup",
            "memory_ingest",
            "memory_quality",
            "memory_graph",
        }

        actual_names = {t.name for t in tools}
        assert actual_names == expected_names, f"Tool mismatch. Missing: {expected_names - actual_names}, Extra: {actual_names - expected_names}"

    @pytest.mark.asyncio
    async def test_old_tools_not_listed(self, server):
        """Verify deprecated tools not in listing."""
        result = await server.list_tools()
        tools = result.tools
        tool_names = {t.name for t in tools}

        deprecated_names = [
            "delete_by_tag",
            "retrieve_memory",
            "consolidation_status",
            "store_memory",
            "list_memories",
            "rate_memory",
            "find_connected_memories",
        ]

        for name in deprecated_names:
            assert name not in tool_names, f"Deprecated tool '{name}' should not be listed"


class TestDeprecatedToolCalls:
    """Test that deprecated tool calls still work."""

    @pytest.mark.asyncio
    async def test_delete_by_tag_still_works(self, server, unique_content):
        """Test deprecated delete_by_tag routes correctly."""
        # First store a memory using new name
        content = unique_content()
        store_result = await server.call_tool(
            "memory_store",
            {"content": content, "metadata": {"tags": "test-delete-deprecated"}}
        )

        # Now delete using old deprecated name
        result = await server.call_tool(
            "delete_by_tag",
            {"tag": "test-delete-deprecated"}
        )

        # Extract result from TextContent
        assert len(result) > 0
        assert isinstance(result[0], TextContent)
        result_data = json.loads(result[0].text)

        # Should either succeed or return 0 deleted (if already deleted)
        assert "error" not in result_data or result_data.get("deleted_count", 0) >= 0

    @pytest.mark.asyncio
    async def test_retrieve_memory_still_works(self, server):
        """Test deprecated retrieve_memory routes correctly."""
        result = await server.call_tool(
            "retrieve_memory",
            {"query": "test search query", "n_results": 5}
        )

        assert len(result) > 0
        assert isinstance(result[0], TextContent)
        result_data = json.loads(result[0].text)

        # Should return memories array or error
        assert "memories" in result_data or "error" in result_data

    @pytest.mark.asyncio
    async def test_store_memory_still_works(self, server, unique_content):
        """Test deprecated store_memory routes correctly."""
        content = unique_content()
        result = await server.call_tool(
            "store_memory",
            {"content": content, "metadata": {"tags": "test-store"}}
        )

        assert len(result) > 0
        assert isinstance(result[0], TextContent)
        result_data = json.loads(result[0].text)

        # Should return content_hash
        assert "content_hash" in result_data or "error" not in result_data

    @pytest.mark.asyncio
    async def test_list_memories_still_works(self, server):
        """Test deprecated list_memories routes correctly."""
        result = await server.call_tool(
            "list_memories",
            {"limit": 5}
        )

        assert len(result) > 0
        assert isinstance(result[0], TextContent)
        result_data = json.loads(result[0].text)

        # Should return memories array
        assert "memories" in result_data or "error" in result_data

    @pytest.mark.asyncio
    async def test_consolidation_status_still_works(self, server):
        """Test deprecated consolidation_status routes correctly."""
        result = await server.call_tool(
            "consolidation_status",
            {}
        )

        assert len(result) > 0
        assert isinstance(result[0], TextContent)
        result_data = json.loads(result[0].text)

        # Should return status dict or error
        assert isinstance(result_data, dict)


class TestNewToolCalls:
    """Test new unified tools work correctly."""

    @pytest.mark.asyncio
    async def test_memory_store(self, server, unique_content):
        """Test memory_store works."""
        content = unique_content()
        result = await server.call_tool(
            "memory_store",
            {"content": content, "metadata": {"tags": "test-new-store"}}
        )

        assert len(result) > 0
        assert isinstance(result[0], TextContent)
        result_data = json.loads(result[0].text)

        assert "content_hash" in result_data
        assert result_data.get("content") == content

    @pytest.mark.asyncio
    async def test_memory_delete_by_hash(self, server, unique_content):
        """Test memory_delete with hash."""
        # Store first
        content = unique_content()
        store_result = await server.call_tool(
            "memory_store",
            {"content": content}
        )
        store_data = json.loads(store_result[0].text)
        content_hash = store_data.get("content_hash")

        if content_hash:
            # Delete
            result = await server.call_tool(
                "memory_delete",
                {"content_hash": content_hash}
            )
            result_data = json.loads(result[0].text)
            assert result_data.get("deleted_count", 0) >= 0

    @pytest.mark.asyncio
    async def test_memory_delete_by_tags(self, server, unique_content):
        """Test memory_delete with tags filter."""
        # Store a memory with test tag
        content = unique_content()
        await server.call_tool(
            "memory_store",
            {"content": content, "metadata": {"tags": "test-delete-new"}}
        )

        # Delete using new tool
        result = await server.call_tool(
            "memory_delete",
            {"tags": ["test-delete-new"], "tag_match": "any"}
        )

        result_data = json.loads(result[0].text)
        assert "deleted_count" in result_data or "error" in result_data

    @pytest.mark.asyncio
    async def test_memory_search_semantic(self, server):
        """Test memory_search semantic mode."""
        result = await server.call_tool(
            "memory_search",
            {"query": "python programming", "limit": 5}
        )

        assert len(result) > 0
        assert isinstance(result[0], TextContent)
        result_data = json.loads(result[0].text)
        assert "memories" in result_data

    @pytest.mark.asyncio
    async def test_memory_search_exact(self, server):
        """Test memory_search exact mode."""
        result = await server.call_tool(
            "memory_search",
            {"query": "test exact phrase", "mode": "exact", "limit": 5}
        )

        result_data = json.loads(result[0].text)
        assert "memories" in result_data
        assert result_data.get("mode") == "exact"

    @pytest.mark.asyncio
    async def test_memory_list(self, server):
        """Test memory_list tool."""
        result = await server.call_tool(
            "memory_list",
            {"limit": 10, "offset": 0}
        )

        result_data = json.loads(result[0].text)
        assert "memories" in result_data or "error" in result_data

    @pytest.mark.asyncio
    async def test_memory_consolidate_status(self, server):
        """Test memory_consolidate status action."""
        result = await server.call_tool(
            "memory_consolidate",
            {"action": "status"}
        )

        assert len(result) > 0
        assert isinstance(result[0], TextContent)
        result_data = json.loads(result[0].text)

        # Should return status info or error, not crash
        assert isinstance(result_data, dict)

    @pytest.mark.asyncio
    async def test_memory_health(self, server):
        """Test memory_health tool."""
        result = await server.call_tool(
            "memory_health",
            {}
        )

        result_data = json.loads(result[0].text)
        assert isinstance(result_data, dict)

    @pytest.mark.asyncio
    async def test_memory_stats(self, server):
        """Test memory_stats tool."""
        result = await server.call_tool(
            "memory_stats",
            {}
        )

        result_data = json.loads(result[0].text)
        assert isinstance(result_data, dict)


class TestArgumentTransformations:
    """Test that argument transformations work correctly in practice."""

    @pytest.mark.asyncio
    async def test_n_results_to_limit_transformation(self, server):
        """Test n_results -> limit transformation."""
        # Old tool with n_results
        old_result = await server.call_tool(
            "retrieve_memory",
            {"query": "test", "n_results": 3}
        )

        # New tool with limit
        new_result = await server.call_tool(
            "memory_search",
            {"query": "test", "limit": 3}
        )

        # Both should work
        assert len(old_result) > 0
        assert len(new_result) > 0

    @pytest.mark.asyncio
    async def test_tag_to_tags_transformation(self, server, unique_content):
        """Test tag -> tags transformation."""
        # Store a test memory
        content = unique_content()
        await server.call_tool(
            "memory_store",
            {"content": content, "metadata": {"tags": "transform-test"}}
        )

        # Old tool with singular 'tag'
        old_result = await server.call_tool(
            "delete_by_tag",
            {"tag": "transform-test"}
        )

        # Should work (transform tag -> tags)
        assert len(old_result) > 0
        old_data = json.loads(old_result[0].text)
        assert "error" not in old_data or old_data.get("deleted_count", 0) >= 0

    @pytest.mark.asyncio
    async def test_time_horizon_added_transformation(self, server):
        """Test action parameter added for consolidation."""
        # Old tool implicitly means action='run'
        result = await server.call_tool(
            "consolidate_memories",
            {"time_horizon": "weekly"}
        )

        # Should route to memory_consolidate with action='run'
        assert len(result) > 0
        result_data = json.loads(result[0].text)
        assert isinstance(result_data, dict)
