#!/usr/bin/env python

"""████
 ██    ██    Datature
   ██  ██    Powering Breakthrough AI
     ██

@File    :   test_httpx_error_utils.py
@Author  :   Wei Loon Cheng
@Contact :   developers@datature.io
@License :   Apache License 2.0
@Desc    :   Tests for httpx error utilities.
"""

from unittest.mock import Mock

import httpx
import pytest
from vi.client.errors import extract_error_message_from_httpx_error


@pytest.mark.unit
class TestExtractErrorMessageFromHttpxError:
    """Test extraction of error messages from httpx HTTPStatusError."""

    def test_extract_with_json_message_field(self):
        """Test extraction when response has JSON with 'message' field."""
        # Create a mock response with JSON error
        mock_request = Mock(spec=httpx.Request)
        mock_request.method = "PUT"

        mock_response = Mock(spec=httpx.Response)
        mock_response.status_code = 403
        mock_response.url = "https://storage.googleapis.com/bucket/file.jpg"
        mock_response.request = mock_request
        mock_response.text = '{"message": "Access denied: insufficient permissions"}'
        mock_response.json.return_value = {
            "message": "Access denied: insufficient permissions"
        }

        error = httpx.HTTPStatusError(
            "Client error", request=mock_request, response=mock_response
        )

        result = extract_error_message_from_httpx_error(error)

        assert "HTTP 403 PUT" in result
        assert "storage.googleapis.com" in result
        assert "Access denied: insufficient permissions" in result

    def test_extract_with_nested_error_object(self):
        """Test extraction when response has nested error object (GCS format)."""
        mock_request = Mock(spec=httpx.Request)
        mock_request.method = "PUT"

        mock_response = Mock(spec=httpx.Response)
        mock_response.status_code = 400
        mock_response.url = "https://storage.googleapis.com/bucket/file.jpg"
        mock_response.request = mock_request
        mock_response.text = '{"error": {"message": "Invalid file format"}}'
        mock_response.json.return_value = {"error": {"message": "Invalid file format"}}

        error = httpx.HTTPStatusError(
            "Client error", request=mock_request, response=mock_response
        )

        result = extract_error_message_from_httpx_error(error)

        assert "HTTP 400 PUT" in result
        assert "Invalid file format" in result

    def test_extract_with_error_string_field(self):
        """Test extraction when response has 'error' as a string field."""
        mock_request = Mock(spec=httpx.Request)
        mock_request.method = "POST"

        mock_response = Mock(spec=httpx.Response)
        mock_response.status_code = 500
        mock_response.url = "https://api.example.com/upload"
        mock_response.request = mock_request
        mock_response.text = '{"error": "Internal server error"}'
        mock_response.json.return_value = {"error": "Internal server error"}

        error = httpx.HTTPStatusError(
            "Server error", request=mock_request, response=mock_response
        )

        result = extract_error_message_from_httpx_error(error)

        assert "HTTP 500 POST" in result
        assert "Internal server error" in result

    def test_extract_with_non_json_response(self):
        """Test extraction when response is not JSON."""
        mock_request = Mock(spec=httpx.Request)
        mock_request.method = "GET"

        mock_response = Mock(spec=httpx.Response)
        mock_response.status_code = 404
        mock_response.url = "https://example.com/not-found"
        mock_response.request = mock_request
        mock_response.text = "404 Not Found: The requested resource was not found"
        mock_response.json.side_effect = ValueError("Not JSON")

        error = httpx.HTTPStatusError(
            "Not found", request=mock_request, response=mock_response
        )

        result = extract_error_message_from_httpx_error(error)

        assert "HTTP 404 GET" in result
        assert "404 Not Found" in result
        assert "requested resource was not found" in result

    def test_extract_with_very_long_response(self):
        """Test extraction with very long response text (should be truncated)."""
        mock_request = Mock(spec=httpx.Request)
        mock_request.method = "POST"

        long_text = "Error: " + "x" * 600
        mock_response = Mock(spec=httpx.Response)
        mock_response.status_code = 500
        mock_response.url = "https://example.com/api"
        mock_response.request = mock_request
        mock_response.text = long_text
        mock_response.json.side_effect = ValueError("Not JSON")

        error = httpx.HTTPStatusError(
            "Server error", request=mock_request, response=mock_response
        )

        result = extract_error_message_from_httpx_error(error)

        assert "HTTP 500 POST" in result
        assert "truncated" in result
        # Should be truncated to 500 chars
        assert len(result) < len(long_text) + 100

    def test_extract_with_detail_field(self):
        """Test extraction when response has 'detail' field (FastAPI format)."""
        mock_request = Mock(spec=httpx.Request)
        mock_request.method = "POST"

        mock_response = Mock(spec=httpx.Response)
        mock_response.status_code = 422
        mock_response.url = "https://api.example.com/resource"
        mock_response.request = mock_request
        mock_response.text = '{"detail": "Validation failed for field x"}'
        mock_response.json.return_value = {"detail": "Validation failed for field x"}

        error = httpx.HTTPStatusError(
            "Validation error", request=mock_request, response=mock_response
        )

        result = extract_error_message_from_httpx_error(error)

        assert "HTTP 422 POST" in result
        assert "Validation failed for field x" in result

    def test_extract_with_no_response_attribute(self):
        """Test extraction when error doesn't have response attribute."""
        error = Mock(spec=httpx.HTTPStatusError)
        error.response = None
        del error.response  # Remove the attribute entirely

        result = extract_error_message_from_httpx_error(error)

        # Should fall back to string representation
        assert result == str(error)
