"""Test suite for Phase 3.1: Registry-based Tool Discovery using FastMCP Client SDK."""

import os

import pytest
from dotenv import load_dotenv

from .test_helpers import assert_tools_registered, get_registered_tools

# Load environment variables
load_dotenv()

# Test configuration
TEST_EMAIL = os.getenv("TEST_EMAIL_ADDRESS", "test@example.com")


class TestRegistryDiscovery:
    """Test registry-based tool discovery implementation."""

    # Using the global client fixture from conftest.py

    @pytest.mark.asyncio
    async def test_registry_tools_available(self, client):
        """Test that tools are discovered through the registry system.

        Note: The server starts with only 5 core tools enabled by default.
        This test uses assert_tools_registered to check the full registry,
        not just the currently enabled/exposed tools.
        """
        # Get all registered tools from the registry (not just enabled ones)
        registered_tools = await get_registered_tools(client)

        # Verify key service tools are registered in the registry
        expected_services = {
            "gmail": [
                "list_gmail_labels",
                "search_gmail_messages",
                "send_gmail_message",
            ],
            "drive": ["upload_to_drive", "search_drive_files", "list_drive_items"],
            "calendar": ["list_calendars", "list_events", "create_event"],
            "docs": ["search_docs", "get_doc_content", "create_doc"],
            "sheets": ["list_spreadsheets", "read_sheet_values", "modify_sheet_values"],
            "slides": ["create_presentation", "add_slide", "export_presentation"],
            "forms": ["create_form", "add_questions_to_form", "list_form_responses"],
            "chat": ["list_spaces", "send_message", "send_card_message"],
            "photos": ["list_photos_albums", "search_photos", "create_photos_album"],
        }

        discovered_services = {}
        for service, service_tools in expected_services.items():
            discovered_services[service] = []
            for tool in service_tools:
                if tool in registered_tools:
                    discovered_services[service].append(tool)

        # Each service should have at least some tools registered
        for service, tools_found in discovered_services.items():
            assert len(tools_found) > 0, (
                f"No tools registered for {service} service in registry"
            )

        print("Registry discovery found tools for all services")
        for service, tools in discovered_services.items():
            print(f"   {service}: {len(tools)} tools registered")

    @pytest.mark.asyncio
    async def test_registry_dynamic_loading(self, client):
        """Test that registry supports dynamic tool loading.

        Note: The server starts with only 5 core tools enabled by default.
        This test checks the full registry via get_registered_tools, then
        enables all tools to verify metadata.
        """
        # Get all registered tools from the registry (not just enabled ones)
        registered_tools = await get_registered_tools(client)
        initial_count = len(registered_tools)

        print(f"Registered tool count: {initial_count}")

        # Verify registry has loaded a substantial number of tools
        # The system should have at least 80+ tools from all services
        assert initial_count > 80, (
            f"Registry should have 80+ tools registered, found {initial_count}"
        )

        # Enable all tools to check metadata
        await client.call_tool("manage_tools", {"action": "enable_all"})

        # Now get enabled tools and check their metadata
        enabled_tools = await client.list_tools()
        sample_tools = enabled_tools[:5]  # Check first 5 tools
        for tool in sample_tools:
            assert tool.name, "Tool should have a name from registry"
            assert tool.description, "Tool should have a description from registry"
            assert hasattr(tool, "inputSchema"), (
                "Tool should have input schema from registry"
            )

    @pytest.mark.asyncio
    async def test_registry_service_grouping(self, client):
        """Test that registry properly groups tools by service.

        Note: The server starts with only 5 core tools enabled by default.
        This test uses get_registered_tools() to analyze the full registry
        and groups tools by service based on naming patterns.
        """
        # Get all registered tools from the registry (not just enabled ones)
        registered_tools = await get_registered_tools(client)

        # Group tools by service prefix based on tool names
        service_groups = {}
        for tool_name in registered_tools:
            # Most Google service tools follow naming patterns
            if (
                tool_name.startswith("list_")
                or tool_name.startswith("create_")
                or tool_name.startswith("send_")
                or tool_name.startswith("search_")
                or tool_name.startswith("get_")
                or tool_name.startswith("upload_")
            ):
                # Extract service from tool name patterns
                name_lower = tool_name.lower()
                if "gmail" in name_lower:
                    service = "gmail"
                elif "drive" in name_lower:
                    service = "drive"
                elif "calendar" in name_lower or "event" in name_lower:
                    service = "calendar"
                elif "doc" in name_lower:
                    service = "docs"
                elif "sheet" in name_lower or "spreadsheet" in name_lower:
                    service = "sheets"
                elif "slide" in name_lower or "presentation" in name_lower:
                    service = "slides"
                elif "form" in name_lower:
                    service = "forms"
                elif (
                    "chat" in name_lower
                    or "space" in name_lower
                    or "card" in name_lower
                ):
                    service = "chat"
                elif "photo" in name_lower or "album" in name_lower:
                    service = "photos"
                else:
                    service = "other"

                if service not in service_groups:
                    service_groups[service] = []
                service_groups[service].append(tool_name)

        # Verify we have tools grouped by service
        expected_services = ["gmail", "drive", "calendar", "docs", "sheets", "chat"]
        for service in expected_services:
            assert service in service_groups, (
                f"Registry should have tools registered for {service}"
            )
            assert len(service_groups[service]) > 0, (
                f"Registry should have tools for {service}"
            )

        print("Registry groups tools by service:")
        for service, tools in service_groups.items():
            print(f"   {service}: {len(tools)} tools")

    @pytest.mark.asyncio
    async def test_registry_tool_metadata(self, client):
        """Test that registry provides complete metadata for tools.

        Note: The server starts with only 5 core tools enabled by default.
        This test verifies the tool is registered and has metadata via
        the manage_tools list action which returns ToolInfo with descriptions.
        """
        import json

        # First verify the tool is registered
        await assert_tools_registered(
            client, ["list_gmail_labels"], "checking gmail labels tool"
        )

        # Get tool info with descriptions from manage_tools list action
        result = await client.call_tool("manage_tools", {"action": "list"})
        content = (
            result.content[0].text
            if hasattr(result.content[0], "text")
            else str(result.content[0])
        )
        data = json.loads(content)

        # Find the gmail labels tool in the tool list
        gmail_label_tool = None
        for tool in data.get("toolList", []):
            if tool["name"] == "list_gmail_labels":
                gmail_label_tool = tool
                break

        assert gmail_label_tool is not None, (
            "list_gmail_labels tool should be in manage_tools list"
        )

        # Check metadata completeness from ToolInfo
        assert gmail_label_tool.get("name"), "Tool should have name"
        assert gmail_label_tool.get("description"), (
            "Tool should have description from registry"
        )
        assert "enabled" in gmail_label_tool, "Tool should have enabled status"

        print("Registry provides complete metadata for tools")
        print(f"   Tool: {gmail_label_tool['name']}")
        desc = gmail_label_tool["description"]
        print(f"   Description: {desc[:100] if len(desc) > 100 else desc}...")

    @pytest.mark.asyncio
    async def test_registry_hot_reload_capability(self, client):
        """Test that registry supports hot-reload of tool definitions.

        Note: This test verifies consistency of list_tools() calls.
        It works with the default enabled tools (no need to enable all).
        """
        # Get tools twice to verify consistency
        tools_1 = await client.list_tools()
        tools_2 = await client.list_tools()

        tool_names_1 = set(tool.name for tool in tools_1)
        tool_names_2 = set(tool.name for tool in tools_2)

        # Tool lists should be consistent across calls
        assert tool_names_1 == tool_names_2, (
            "Registry should provide consistent tool list"
        )

        print("Registry provides consistent tool discovery")
        print(f"   Total tools: {len(tools_1)}")
        print("   Consistency verified across multiple calls")

    @pytest.mark.asyncio
    async def test_registry_error_handling(self, client):
        """Test registry's error handling for invalid tools."""
        # Try to call a non-existent tool
        try:
            result = await client.call_tool("non_existent_tool_xyz", {})
            # Should not reach here
            assert False, "Should raise error for non-existent tool"
        except Exception as e:
            error_msg = str(e).lower()
            # Should get a clear error about unknown tool
            assert (
                "unknown" in error_msg
                or "not found" in error_msg
                or "invalid" in error_msg
            ), f"Should get clear error for unknown tool, got: {e}"

        print("Registry properly handles invalid tool requests")

    @pytest.mark.asyncio
    async def test_registry_performance(self, client):
        """Test registry tool discovery performance.

        Note: The server starts with only 5 core tools enabled by default.
        This test measures the performance of querying the full registry
        via manage_tools list action, which returns all registered tools.
        """
        import time

        # Measure time to query full registry via manage_tools
        start_time = time.time()
        registered_tools = await get_registered_tools(client)
        registry_time = time.time() - start_time

        # Registry query should be fast (under 2 seconds)
        assert registry_time < 2.0, (
            f"Registry query took {registry_time:.2f}s, should be under 2s"
        )

        # Verify we got a reasonable number of tools registered
        assert len(registered_tools) > 50, (
            f"Expected 50+ tools registered, got {len(registered_tools)}"
        )

        # Also measure list_tools performance for enabled tools
        start_time = time.time()
        tools = await client.list_tools()
        discovery_time = time.time() - start_time

        # Discovery should be fast (under 2 seconds)
        assert discovery_time < 2.0, (
            f"Tool discovery took {discovery_time:.2f}s, should be under 2s"
        )

        print("Registry tool discovery performance:")
        print(
            f"   Registry has {len(registered_tools)} tools (queried in {registry_time:.3f}s)"
        )
        print(
            f"   Currently {len(tools)} tools enabled (discovered in {discovery_time:.3f}s)"
        )
        print(
            f"   Average registry query: {(registry_time * 1000) / len(registered_tools):.2f}ms per tool"
        )


class TestRegistryIntegration:
    """Test registry integration with other components."""

    # Using the global client fixture from conftest.py

    @pytest.mark.asyncio
    async def test_registry_with_middleware(self, client):
        """Test that registry works with middleware components.

        Note: The server starts with only 5 core tools enabled by default.
        This test enables all tools first to test middleware integration.
        """
        # Enable all tools first
        await client.call_tool("manage_tools", {"action": "enable_all"})

        # Call a tool that requires middleware (template resolution)
        result = await client.call_tool(
            "list_gmail_labels", {"user_google_email": TEST_EMAIL}
        )

        assert result is not None, "Registry should work with middleware"
        content = result.content[0].text

        # Should get a response (auth error or success)
        assert len(content) > 0, "Should get response through registry + middleware"

        print("Registry integrates with middleware")
        print(f"   Response length: {len(content)} chars")

    @pytest.mark.asyncio
    async def test_registry_with_auth_patterns(self, client):
        """Test registry tools work with authentication patterns.

        Note: The server starts with only 5 core tools enabled by default.
        This test enables all tools first to test auth patterns.
        """
        # Enable all tools first
        await client.call_tool("manage_tools", {"action": "enable_all"})

        # Test tools that require authentication
        auth_required_tools = [
            ("list_gmail_labels", {"user_google_email": TEST_EMAIL}),
            ("list_calendars", {"user_google_email": TEST_EMAIL}),
            ("list_drive_items", {"user_google_email": TEST_EMAIL}),
        ]

        for tool_name, params in auth_required_tools:
            result = await client.call_tool(tool_name, params)
            assert result is not None, f"{tool_name} should work through registry"

            content = result.content[0].text
            # Should get auth error or success
            assert len(content) > 0, f"{tool_name} should return response"

        print("Registry tools work with auth patterns")
        print(f"   Tested {len(auth_required_tools)} auth-required tools")

    @pytest.mark.asyncio
    async def test_registry_tool_routing(self, client):
        """Test that registry properly routes tools to correct handlers.

        Note: The server starts with only 5 core tools enabled by default.
        This test enables all tools first to test routing.
        """
        # Enable all tools first
        await client.call_tool("manage_tools", {"action": "enable_all"})

        # Test tools from different services
        test_cases = [
            ("list_gmail_labels", "gmail"),
            ("list_calendars", "calendar"),
            ("list_drive_items", "drive"),
            ("list_spaces", "chat"),
        ]

        tools = await client.list_tools()
        tool_names = [tool.name for tool in tools]

        for tool_name, expected_service in test_cases:
            if tool_name in tool_names:
                # Tool should be routed to correct service
                tool = next((t for t in tools if t.name == tool_name), None)
                assert tool is not None, f"{tool_name} should be in registry"

                # Description should mention the service
                desc_lower = tool.description.lower()
                assert (
                    expected_service in desc_lower
                    or tool_name.replace("_", " ") in desc_lower
                ), f"{tool_name} should be associated with {expected_service}"

        print("Registry properly routes tools to services")
        print(f"   Verified routing for {len(test_cases)} tools")


if __name__ == "__main__":
    pytest.main([__file__, "-v"])
