"""Tests for the HTTP client."""

from unittest.mock import AsyncMock, MagicMock, patch

import pytest

from aal_sdk.errors import AALError
from aal_sdk.http import HttpClient


@pytest.fixture
def http_client():
    """Create an HttpClient instance."""
    return HttpClient("https://api.example.com", "test-api-key")


async def test_bearer_auth_header_is_set(http_client: HttpClient):
    """Test that the Authorization header is set with Bearer token."""
    # Access the internal client's headers
    headers = http_client._client.headers
    assert headers["authorization"] == "Bearer test-api-key"
    await http_client.close()


async def test_base_url_trailing_slash_stripped():
    """Test that trailing slashes are stripped from base URL."""
    client = HttpClient("https://api.example.com/", "key")
    assert client._base_url == "https://api.example.com"
    await client.close()


async def test_get_request(http_client: HttpClient):
    """Test GET request returns parsed JSON."""
    mock_response = MagicMock()
    mock_response.status_code = 200
    mock_response.json.return_value = {"data": [1, 2, 3]}

    with patch.object(http_client._client, "request", new_callable=AsyncMock) as mock_req:
        mock_req.return_value = mock_response
        result = await http_client.get("/v1/events")

    assert result == {"data": [1, 2, 3]}
    mock_req.assert_called_once_with("GET", "/v1/events")
    await http_client.close()


async def test_post_request_with_body(http_client: HttpClient):
    """Test POST request sends JSON body."""
    mock_response = MagicMock()
    mock_response.status_code = 201
    mock_response.json.return_value = {"created": 2}

    with patch.object(http_client._client, "request", new_callable=AsyncMock) as mock_req:
        mock_req.return_value = mock_response
        result = await http_client.post("/v1/events/batch", {"events": []})

    assert result == {"created": 2}
    mock_req.assert_called_once_with("POST", "/v1/events/batch", json={"events": []})
    await http_client.close()


async def test_aal_error_on_400_response(http_client: HttpClient):
    """Test AALError is raised on 400 response."""
    mock_response = MagicMock()
    mock_response.status_code = 400
    mock_response.json.return_value = {
        "error": {
            "message": "Invalid session_id",
            "code": "VALIDATION_ERROR",
            "requestId": "req-123",
        }
    }

    with patch.object(http_client._client, "request", new_callable=AsyncMock) as mock_req:
        mock_req.return_value = mock_response
        with pytest.raises(AALError) as exc_info:
            await http_client.get("/v1/events")

    err = exc_info.value
    assert err.status == 400
    assert err.code == "VALIDATION_ERROR"
    assert str(err) == "Invalid session_id"
    assert err.request_id == "req-123"
    await http_client.close()


async def test_aal_error_on_500_response(http_client: HttpClient):
    """Test AALError is raised on 500 response."""
    mock_response = MagicMock()
    mock_response.status_code = 500
    mock_response.json.return_value = {
        "error": {
            "message": "Internal server error",
            "code": "INTERNAL_ERROR",
        }
    }

    with patch.object(http_client._client, "request", new_callable=AsyncMock) as mock_req:
        mock_req.return_value = mock_response
        with pytest.raises(AALError) as exc_info:
            await http_client.get("/v1/events")

    err = exc_info.value
    assert err.status == 500
    assert err.code == "INTERNAL_ERROR"
    assert err.request_id is None
    await http_client.close()


async def test_fallback_error_when_json_parse_fails(http_client: HttpClient):
    """Test fallback error body when JSON parsing fails."""
    mock_response = MagicMock()
    mock_response.status_code = 502
    mock_response.json.side_effect = Exception("Not JSON")

    with patch.object(http_client._client, "request", new_callable=AsyncMock) as mock_req:
        mock_req.return_value = mock_response
        with pytest.raises(AALError) as exc_info:
            await http_client.get("/v1/events")

    err = exc_info.value
    assert err.status == 502
    assert err.code == "UNKNOWN_ERROR"
    assert str(err) == "HTTP 502"
    await http_client.close()
