"""Unit tests for version management tools."""

import json
from unittest.mock import AsyncMock, MagicMock, patch

import pytest
from mcp.server.fastmcp import Context

from src.mcp_server.features.documents.version_tools import register_version_tools


@pytest.fixture
def mock_mcp():
    """Create a mock MCP server for testing."""
    mock = MagicMock()
    # Store registered tools
    mock._tools = {}

    def tool_decorator():
        def decorator(func):
            mock._tools[func.__name__] = func
            return func

        return decorator

    mock.tool = tool_decorator
    return mock


@pytest.fixture
def mock_context():
    """Create a mock context for testing."""
    return MagicMock(spec=Context)


@pytest.mark.asyncio
async def test_create_version_success(mock_mcp, mock_context):
    """Test successful version creation."""
    register_version_tools(mock_mcp)

    # Get the create_version function
    create_version = mock_mcp._tools.get("create_version")

    assert create_version is not None, "create_version tool not registered"

    # Mock HTTP response
    mock_response = MagicMock()
    mock_response.status_code = 200
    mock_response.json.return_value = {
        "version": {"version_number": 3, "field_name": "docs"},
        "message": "Version created successfully",
    }

    with patch("src.mcp_server.features.documents.version_tools.httpx.AsyncClient") as mock_client:
        mock_async_client = AsyncMock()
        mock_async_client.post.return_value = mock_response
        mock_client.return_value.__aenter__.return_value = mock_async_client

        result = await create_version(
            mock_context,
            project_id="project-123",
            field_name="docs",
            content=[{"id": "doc-1", "title": "Test Doc"}],
            change_summary="Added test document",
        )

        result_data = json.loads(result)
        assert result_data["success"] is True
        assert result_data["version_number"] == 3
        assert "Version 3 created successfully" in result_data["message"]


@pytest.mark.asyncio
async def test_create_version_invalid_field(mock_mcp, mock_context):
    """Test version creation with invalid field name."""
    register_version_tools(mock_mcp)

    create_version = mock_mcp._tools.get("create_version")

    # Mock 400 response for invalid field
    mock_response = MagicMock()
    mock_response.status_code = 400
    mock_response.text = "invalid field_name"

    with patch("src.mcp_server.features.documents.version_tools.httpx.AsyncClient") as mock_client:
        mock_async_client = AsyncMock()
        mock_async_client.post.return_value = mock_response
        mock_client.return_value.__aenter__.return_value = mock_async_client

        result = await create_version(
            mock_context, project_id="project-123", field_name="invalid", content={"test": "data"}
        )

        result_data = json.loads(result)
        assert result_data["success"] is False
        # Error must be structured format (dict), not string
        assert "error" in result_data
        assert isinstance(result_data["error"], dict), (
            "Error should be structured format, not string"
        )
        assert result_data["error"]["type"] == "validation_error"


@pytest.mark.asyncio
async def test_restore_version_success(mock_mcp, mock_context):
    """Test successful version restoration."""
    register_version_tools(mock_mcp)

    # Get the restore_version function
    restore_version = mock_mcp._tools.get("restore_version")

    assert restore_version is not None, "restore_version tool not registered"

    # Mock HTTP response
    mock_response = MagicMock()
    mock_response.status_code = 200
    mock_response.json.return_value = {"message": "Version 2 restored successfully"}

    with patch("src.mcp_server.features.documents.version_tools.httpx.AsyncClient") as mock_client:
        mock_async_client = AsyncMock()
        mock_async_client.post.return_value = mock_response
        mock_client.return_value.__aenter__.return_value = mock_async_client

        result = await restore_version(
            mock_context,
            project_id="project-123",
            field_name="docs",
            version_number=2,
            restored_by="test-user",
        )

        result_data = json.loads(result)
        assert result_data["success"] is True
        assert "Version 2 restored successfully" in result_data["message"]


@pytest.mark.asyncio
async def test_list_versions_with_filter(mock_mcp, mock_context):
    """Test listing versions with field name filter."""
    register_version_tools(mock_mcp)

    # Get the list_versions function
    list_versions = mock_mcp._tools.get("list_versions")

    assert list_versions is not None, "list_versions tool not registered"

    # Mock HTTP response
    mock_response = MagicMock()
    mock_response.status_code = 200
    mock_response.json.return_value = {
        "versions": [
            {"version_number": 1, "field_name": "docs", "change_summary": "Initial"},
            {"version_number": 2, "field_name": "docs", "change_summary": "Updated"},
        ]
    }

    with patch("src.mcp_server.features.documents.version_tools.httpx.AsyncClient") as mock_client:
        mock_async_client = AsyncMock()
        mock_async_client.get.return_value = mock_response
        mock_client.return_value.__aenter__.return_value = mock_async_client

        result = await list_versions(mock_context, project_id="project-123", field_name="docs")

        result_data = json.loads(result)
        assert result_data["success"] is True
        assert result_data["count"] == 2
        assert len(result_data["versions"]) == 2

        # Verify filter was passed
        call_args = mock_async_client.get.call_args
        assert call_args[1]["params"]["field_name"] == "docs"
