"""Unit tests for MCPErrorFormatter utility."""

import json
from unittest.mock import MagicMock

import httpx
import pytest

from src.mcp_server.utils.error_handling import MCPErrorFormatter


def test_format_error_basic():
    """Test basic error formatting."""
    result = MCPErrorFormatter.format_error(
        error_type="validation_error",
        message="Invalid input",
    )

    result_data = json.loads(result)
    assert result_data["success"] is False
    assert result_data["error"]["type"] == "validation_error"
    assert result_data["error"]["message"] == "Invalid input"
    assert "details" not in result_data["error"]
    assert "suggestion" not in result_data["error"]


def test_format_error_with_all_fields():
    """Test error formatting with all optional fields."""
    result = MCPErrorFormatter.format_error(
        error_type="connection_timeout",
        message="Connection timed out",
        details={"url": "http://api.example.com", "timeout": 30},
        suggestion="Check network connectivity",
        http_status=504,
    )

    result_data = json.loads(result)
    assert result_data["success"] is False
    assert result_data["error"]["type"] == "connection_timeout"
    assert result_data["error"]["message"] == "Connection timed out"
    assert result_data["error"]["details"]["url"] == "http://api.example.com"
    assert result_data["error"]["suggestion"] == "Check network connectivity"
    assert result_data["error"]["http_status"] == 504


def test_from_http_error_with_json_body():
    """Test formatting from HTTP response with JSON error body."""
    mock_response = MagicMock(spec=httpx.Response)
    mock_response.status_code = 400
    mock_response.json.return_value = {
        "detail": {"error": "Field is required"},
        "message": "Validation failed",
    }

    result = MCPErrorFormatter.from_http_error(mock_response, "create item")

    result_data = json.loads(result)
    assert result_data["success"] is False
    # When JSON body has error details, it returns api_error, not http_error
    assert result_data["error"]["type"] == "api_error"
    assert "Field is required" in result_data["error"]["message"]
    assert result_data["error"]["http_status"] == 400


def test_from_http_error_with_text_body():
    """Test formatting from HTTP response with text error body."""
    mock_response = MagicMock(spec=httpx.Response)
    mock_response.status_code = 404
    mock_response.json.side_effect = json.JSONDecodeError("msg", "doc", 0)
    mock_response.text = "Resource not found"

    result = MCPErrorFormatter.from_http_error(mock_response, "get item")

    result_data = json.loads(result)
    assert result_data["success"] is False
    assert result_data["error"]["type"] == "http_error"
    # The message format is "Failed to {operation}: HTTP {status_code}"
    assert "Failed to get item: HTTP 404" == result_data["error"]["message"]
    assert result_data["error"]["http_status"] == 404


def test_from_exception_timeout():
    """Test formatting from timeout exception."""
    # httpx.TimeoutException is a subclass of httpx.RequestError
    exception = httpx.TimeoutException("Request timed out after 30s")

    result = MCPErrorFormatter.from_exception(
        exception, "fetch data", {"url": "http://api.example.com"}
    )

    result_data = json.loads(result)
    assert result_data["success"] is False
    # TimeoutException is categorized as request_error since it's a RequestError subclass
    assert result_data["error"]["type"] == "request_error"
    assert "Request timed out" in result_data["error"]["message"]
    assert result_data["error"]["details"]["context"]["url"] == "http://api.example.com"
    assert "network connectivity" in result_data["error"]["suggestion"].lower()


def test_from_exception_connection():
    """Test formatting from connection exception."""
    exception = httpx.ConnectError("Failed to connect to host")

    result = MCPErrorFormatter.from_exception(exception, "connect to API")

    result_data = json.loads(result)
    assert result_data["success"] is False
    assert result_data["error"]["type"] == "connection_error"
    assert "Failed to connect" in result_data["error"]["message"]
    # The actual suggestion is "Ensure the Archon server is running on the correct port"
    assert "archon server" in result_data["error"]["suggestion"].lower()


def test_from_exception_request_error():
    """Test formatting from generic request error."""
    exception = httpx.RequestError("Network error")

    result = MCPErrorFormatter.from_exception(exception, "make request")

    result_data = json.loads(result)
    assert result_data["success"] is False
    assert result_data["error"]["type"] == "request_error"
    assert "Network error" in result_data["error"]["message"]
    assert "network connectivity" in result_data["error"]["suggestion"].lower()


def test_from_exception_generic():
    """Test formatting from generic exception."""
    exception = ValueError("Invalid value")

    result = MCPErrorFormatter.from_exception(exception, "process data")

    result_data = json.loads(result)
    assert result_data["success"] is False
    # ValueError is specifically categorized as validation_error
    assert result_data["error"]["type"] == "validation_error"
    assert "process data" in result_data["error"]["message"]
    assert "Invalid value" in result_data["error"]["details"]["exception_message"]


def test_from_exception_connect_timeout():
    """Test formatting from connect timeout exception."""
    exception = httpx.ConnectTimeout("Connection timed out")

    result = MCPErrorFormatter.from_exception(exception, "connect to API")

    result_data = json.loads(result)
    assert result_data["success"] is False
    assert result_data["error"]["type"] == "connection_timeout"
    assert "Connection timed out" in result_data["error"]["message"]
    assert "server is running" in result_data["error"]["suggestion"].lower()


def test_from_exception_read_timeout():
    """Test formatting from read timeout exception."""
    exception = httpx.ReadTimeout("Read timed out")

    result = MCPErrorFormatter.from_exception(exception, "read data")

    result_data = json.loads(result)
    assert result_data["success"] is False
    assert result_data["error"]["type"] == "read_timeout"
    assert "Read timed out" in result_data["error"]["message"]
    assert "taking longer than expected" in result_data["error"]["suggestion"].lower()
