"""Chaos — Error body parsing: malformed, non-JSON, empty, rate limit details."""

from __future__ import annotations

import httpx
import pytest
import respx

from kanoniv.client.client import KanonivClient
from kanoniv.exceptions import KanonivError, RateLimitError, ServerError

from .conftest import API_KEY, BASE_URL


# ---------------------------------------------------------------------------
# Non-JSON error bodies
# ---------------------------------------------------------------------------

class TestNonJsonErrorBodies:
    """Error parsing is robust against malformed, missing, or unexpected bodies."""

    def test_plain_text_body(self, mock_api: respx.Router, client: KanonivClient):
        mock_api.get("/v1/stats").mock(
            return_value=httpx.Response(500, text="Internal Server Error"),
        )
        with pytest.raises(ServerError) as exc_info:
            client.stats()
        assert exc_info.value.body == "Internal Server Error"

    def test_html_body(self, mock_api: respx.Router, client: KanonivClient):
        mock_api.get("/v1/stats").mock(
            return_value=httpx.Response(502, text="<html><body>Bad Gateway</body></html>"),
        )
        with pytest.raises(ServerError) as exc_info:
            client.stats()
        assert "<html>" in exc_info.value.body

    def test_empty_body(self, mock_api: respx.Router, client: KanonivClient):
        mock_api.get("/v1/stats").mock(
            return_value=httpx.Response(500, text=""),
        )
        with pytest.raises(ServerError) as exc_info:
            client.stats()
        assert exc_info.value.body == ""

    def test_json_without_error_key(self, mock_api: respx.Router, client: KanonivClient):
        mock_api.get("/v1/stats").mock(
            return_value=httpx.Response(400, json={"message": "something wrong"}),
        )
        with pytest.raises(KanonivError) as exc_info:
            client.stats()
        assert isinstance(exc_info.value.body, dict)

    def test_json_with_error_key(self, mock_api: respx.Router, client: KanonivClient):
        mock_api.get("/v1/stats").mock(
            return_value=httpx.Response(400, json={"error": "field required"}),
        )
        with pytest.raises(KanonivError) as exc_info:
            client.stats()
        assert "field required" in str(exc_info.value)


# ---------------------------------------------------------------------------
# Rate limit details
# ---------------------------------------------------------------------------

class TestRateLimitDetails:
    """429 responses preserve Retry-After and body details."""

    def test_integer_retry_after(self, mock_api: respx.Router, client: KanonivClient):
        mock_api.get("/v1/stats").mock(
            return_value=httpx.Response(
                429, json={"error": "too fast"},
                headers={"Retry-After": "5"},
            ),
        )
        with pytest.raises(RateLimitError) as exc_info:
            client.stats()
        assert exc_info.value.retry_after == pytest.approx(5.0)

    def test_float_retry_after(self, mock_api: respx.Router, client: KanonivClient):
        mock_api.get("/v1/stats").mock(
            return_value=httpx.Response(
                429, json={"error": "too fast"},
                headers={"Retry-After": "2.5"},
            ),
        )
        with pytest.raises(RateLimitError) as exc_info:
            client.stats()
        assert exc_info.value.retry_after == pytest.approx(2.5)

    def test_no_retry_after_is_none(self, mock_api: respx.Router, client: KanonivClient):
        mock_api.get("/v1/stats").mock(
            return_value=httpx.Response(429, json={"error": "too fast"}),
        )
        with pytest.raises(RateLimitError) as exc_info:
            client.stats()
        assert exc_info.value.retry_after is None

    def test_body_preserved(self, mock_api: respx.Router, client: KanonivClient):
        body = {"error": "rate limited", "quota": 1000}
        mock_api.get("/v1/stats").mock(
            return_value=httpx.Response(429, json=body),
        )
        with pytest.raises(RateLimitError) as exc_info:
            client.stats()
        assert exc_info.value.body == body

    def test_status_code_429(self, mock_api: respx.Router, client: KanonivClient):
        mock_api.get("/v1/stats").mock(
            return_value=httpx.Response(429, json={"error": "too fast"}),
        )
        with pytest.raises(RateLimitError) as exc_info:
            client.stats()
        assert exc_info.value.status_code == 429
