"""Tests for deprecated tool serializer functionality.

These tests verify that serializer parameters still work but are deprecated.
All serializer-related tests should be moved here.
"""

import warnings

import pytest
from inline_snapshot import snapshot
from mcp.types import TextContent

from fastmcp import FastMCP
from fastmcp.contrib.mcp_mixin import mcp_tool
from fastmcp.server.providers import LocalProvider
from fastmcp.tools.base import Tool, _convert_to_content
from fastmcp.tools.tool_transform import TransformedTool
from fastmcp.utilities.tests import temporary_settings


class TestToolSerializerDeprecated:
    """Tests for deprecated serializer functionality."""

    async def test_tool_serializer(self):
        """Test that a tool's serializer is used to serialize the result."""

        def custom_serializer(data) -> str:
            return f"Custom serializer: {data}"

        def process_list(items: list[int]) -> int:
            return sum(items)

        tool = Tool.from_function(process_list, serializer=custom_serializer)

        result = await tool.run(arguments={"items": [1, 2, 3, 4, 5]})
        # Custom serializer affects unstructured content
        assert isinstance(result.content[0], TextContent)
        assert result.content[0].text == "Custom serializer: 15"
        # Structured output should have the raw value
        assert result.structured_content == {"result": 15}

    def test_custom_serializer(self):
        """Test that a custom serializer is used for non-MCP types."""

        def custom_serializer(data):
            return f"Serialized: {data}"

        result = _convert_to_content({"a": 1}, serializer=custom_serializer)

        assert result == snapshot(
            [TextContent(type="text", text="Serialized: {'a': 1}")]
        )

    def test_custom_serializer_error_fallback(self, caplog):
        """Test that if a custom serializer fails, it falls back to the default."""

        def custom_serializer_that_fails(data):
            raise ValueError("Serialization failed")

        result = _convert_to_content({"a": 1}, serializer=custom_serializer_that_fails)

        assert isinstance(result, list)
        assert result == snapshot([TextContent(type="text", text='{"a":1}')])

        assert "Error serializing tool result" in caplog.text


class TestSerializerDeprecationWarnings:
    """Tests that deprecation warnings are raised when serializer is used."""

    def test_tool_from_function_serializer_warning(self):
        """Test that Tool.from_function warns when serializer is provided."""

        def custom_serializer(data) -> str:
            return f"Custom: {data}"

        def my_tool(x: int) -> int:
            return x * 2

        with temporary_settings(deprecation_warnings=True):
            with pytest.warns(DeprecationWarning, match="serializer.*deprecated"):
                Tool.from_function(my_tool, serializer=custom_serializer)

    def test_tool_from_function_serializer_no_warning_when_disabled(self):
        """Test that no warning is raised when deprecation_warnings is False."""

        def custom_serializer(data) -> str:
            return f"Custom: {data}"

        def my_tool(x: int) -> int:
            return x * 2

        with temporary_settings(deprecation_warnings=False):
            with warnings.catch_warnings():
                warnings.simplefilter("error")
                # Should not raise
                Tool.from_function(my_tool, serializer=custom_serializer)

    def test_local_provider_tool_serializer_warning(self):
        """Test that LocalProvider.tool warns when serializer is provided."""
        provider = LocalProvider()

        def custom_serializer(data) -> str:
            return f"Custom: {data}"

        def my_tool(x: int) -> int:
            return x * 2

        with temporary_settings(deprecation_warnings=True):
            with pytest.warns(DeprecationWarning, match="serializer.*deprecated"):
                provider.tool(my_tool, serializer=custom_serializer)

    def test_local_provider_tool_decorator_serializer_warning(self):
        """Test that LocalProvider.tool decorator warns when serializer is provided."""
        provider = LocalProvider()

        def custom_serializer(data) -> str:
            return f"Custom: {data}"

        with temporary_settings(deprecation_warnings=True):
            with pytest.warns(DeprecationWarning, match="serializer.*deprecated"):

                @provider.tool(serializer=custom_serializer)
                def my_tool(x: int) -> int:
                    return x * 2

    def test_fastmcp_tool_serializer_warning(self):
        """Test that FastMCP.tool warns when serializer is provided via LocalProvider."""

        def custom_serializer(data) -> str:
            return f"Custom: {data}"

        def my_tool(x: int) -> int:
            return x * 2

        # FastMCP.tool doesn't accept serializer directly, it goes through LocalProvider
        # So we test LocalProvider.tool which is what FastMCP uses internally
        provider = LocalProvider()
        with temporary_settings(deprecation_warnings=True):
            with pytest.warns(DeprecationWarning, match="serializer.*deprecated"):
                provider.tool(my_tool, serializer=custom_serializer)

    def test_fastmcp_tool_serializer_parameter_raises_type_error(self):
        """Test that FastMCP tool_serializer parameter raises TypeError."""

        def custom_serializer(data) -> str:
            return f"Custom: {data}"

        with pytest.raises(TypeError, match="no longer accepts `tool_serializer`"):
            FastMCP("TestServer", tool_serializer=custom_serializer)

    def test_transformed_tool_from_tool_serializer_warning(self):
        """Test that TransformedTool.from_tool warns when serializer is provided."""

        def custom_serializer(data) -> str:
            return f"Custom: {data}"

        def my_tool(x: int) -> int:
            return x * 2

        parent_tool = Tool.from_function(my_tool)

        with temporary_settings(deprecation_warnings=True):
            with pytest.warns(DeprecationWarning, match="serializer.*deprecated"):
                TransformedTool.from_tool(parent_tool, serializer=custom_serializer)

    def test_mcp_mixin_tool_serializer_warning(self):
        """Test that mcp_tool decorator warns when serializer is provided."""

        def custom_serializer(data) -> str:
            return f"Custom: {data}"

        with temporary_settings(deprecation_warnings=True):
            with pytest.warns(DeprecationWarning, match="serializer.*deprecated"):

                @mcp_tool(serializer=custom_serializer)
                def my_tool(x: int) -> int:
                    return x * 2
