"""Tests for the retry predicate."""

from __future__ import annotations

from unittest.mock import Mock

import httpx

from github_app.retry import is_retryable


def _make_status_error(status_code: int) -> httpx.HTTPStatusError:
    """Create an HTTPStatusError with the given status code."""
    response = Mock(spec=httpx.Response)
    response.status_code = status_code
    return httpx.HTTPStatusError(
        "error",
        request=Mock(),
        response=response,
    )


# ---------------------------------------------------------------------------
# Retryable cases
# ---------------------------------------------------------------------------


def test_retryable_429():
    assert is_retryable(_make_status_error(429)) is True


def test_retryable_500():
    assert is_retryable(_make_status_error(500)) is True


def test_retryable_502():
    assert is_retryable(_make_status_error(502)) is True


def test_retryable_503():
    assert is_retryable(_make_status_error(503)) is True


def test_retryable_connect_error():
    exc = httpx.ConnectError("connection refused")
    assert is_retryable(exc) is True


def test_retryable_timeout():
    exc = httpx.ReadTimeout("read timed out")
    assert is_retryable(exc) is True


def test_retryable_connect_timeout():
    exc = httpx.ConnectTimeout("connect timed out")
    assert is_retryable(exc) is True


# ---------------------------------------------------------------------------
# Non-retryable cases
# ---------------------------------------------------------------------------


def test_not_retryable_400():
    assert is_retryable(_make_status_error(400)) is False


def test_not_retryable_401():
    assert is_retryable(_make_status_error(401)) is False


def test_not_retryable_403():
    assert is_retryable(_make_status_error(403)) is False


def test_not_retryable_404():
    assert is_retryable(_make_status_error(404)) is False


def test_not_retryable_422():
    assert is_retryable(_make_status_error(422)) is False


def test_not_retryable_value_error():
    assert is_retryable(ValueError("bad")) is False


def test_not_retryable_runtime_error():
    assert is_retryable(RuntimeError("oops")) is False
