# === `Projects/veritell-langchain/tests/test_http_post_json_c11_errors.py` ===
import pytest

from veritell_langchain.errors import (
    RateLimitedError,
    ServiceUnavailableError,
    VeritellAuthError,
    VeritellRequestError,
    VeritellServerError,
)
from veritell_langchain.http import HttpResponse, post_json


class FakeHttpClient:
    def __init__(self, *, response: HttpResponse | None = None, exc: Exception | None = None):
        self._response = response
        self._exc = exc

    def post(self, url: str, *, json, headers=None, timeout_s=None) -> HttpResponse:
        if self._exc is not None:
            raise self._exc
        assert self._response is not None
        return self._response


def test_c11_401_maps_to_auth_error_with_fields() -> None:
    client = FakeHttpClient(
        response=HttpResponse(
            status_code=401,
            json_data={"error": "invalid_api_key", "message": "bad key", "status": 401},
        )
    )
    with pytest.raises(VeritellAuthError) as exc:
        post_json(client, "https://example.test/eval", payload={})
    assert exc.value.status == 401
    assert exc.value.error == "invalid_api_key"
    assert exc.value.message == "bad key"
    assert exc.value.upgrade_url is None


def test_c11_403_maps_to_auth_error() -> None:
    client = FakeHttpClient(
        response=HttpResponse(
            status_code=403,
            json_data={"error": "key_revoked", "message": "revoked", "status": 403},
        )
    )
    with pytest.raises(VeritellAuthError):
        post_json(client, "https://example.test/eval", payload={})


def test_c11_400_maps_to_request_error() -> None:
    client = FakeHttpClient(
        response=HttpResponse(
            status_code=400,
            json_data={"error": "invalid_request", "message": "bad payload", "status": 400},
        )
    )
    with pytest.raises(VeritellRequestError) as exc:
        post_json(client, "https://example.test/eval", payload={})
    assert exc.value.status == 400
    assert exc.value.error == "invalid_request"


def test_c11_429_maps_to_rate_limited_error_and_upgrade_url() -> None:
    client = FakeHttpClient(
        response=HttpResponse(
            status_code=429,
            json_data={
                "error": "plan_limit_exceeded",
                "message": "upgrade needed",
                "status": 429,
                "upgrade_url": "https://veritell.ai/upgrade",
            },
        )
    )
    with pytest.raises(RateLimitedError) as exc:
        post_json(client, "https://example.test/eval", payload={})
    assert exc.value.status == 429
    assert exc.value.upgrade_url == "https://veritell.ai/upgrade"


def test_c11_503_maps_to_service_unavailable_error_and_retry_after() -> None:
    client = FakeHttpClient(
        response=HttpResponse(
            status_code=503,
            json_data={
                "error": "service_unavailable",
                "message": "retry later",
                "status": 503,
                "retry_after_seconds": 30,
            },
        )
    )
    with pytest.raises(ServiceUnavailableError) as exc:
        post_json(client, "https://example.test/eval", payload={})
    assert exc.value.status == 503
    assert exc.value.retry_after_seconds == 30


def test_c11_500_maps_to_server_error() -> None:
    client = FakeHttpClient(
        response=HttpResponse(
            status_code=500,
            json_data={"error": "internal_error", "message": "oops", "status": 500},
        )
    )
    with pytest.raises(VeritellServerError):
        post_json(client, "https://example.test/eval", payload={})


def test_c11_missing_error_shape_is_handled() -> None:
    client = FakeHttpClient(response=HttpResponse(status_code=500, json_data={"x": 1}))
    with pytest.raises(VeritellServerError) as exc:
        post_json(client, "https://example.test/eval", payload={})
    assert exc.value.error == "unknown_error"
