"""Tests for retry logic."""

from __future__ import annotations

import httpx
import pytest
import respx

from presentations_ai import (
    AuthenticationError,
    BadRequestError,
    InternalServerError,
    PresentationsAI,
    RateLimitError,
)

TEST_API_KEY = "pai_test_key"
BASE = "https://developers.presentations.ai"


class TestRetryBehavior:
    @respx.mock
    def test_retries_on_429(self, respx_mock: respx.MockRouter) -> None:
        """429 should be retried, then succeed."""
        route = respx_mock.post(f"{BASE}/api/v1/topic/document").mock(
            side_effect=[
                httpx.Response(429, json={"error": "Rate limited"}),
                httpx.Response(
                    200, json={"status": 0, "docid": 1, "docurl": "http://x"}
                ),
            ]
        )

        with PresentationsAI(api_key=TEST_API_KEY, max_retries=1) as client:
            result = client.create_from_topic(topic="test", export_type="pptx")

        assert result.docid == 1
        assert route.call_count == 2

    @respx.mock
    def test_retries_on_500(self, respx_mock: respx.MockRouter) -> None:
        """5xx should be retried."""
        route = respx_mock.post(f"{BASE}/api/v1/topic/document").mock(
            side_effect=[
                httpx.Response(500, text="Server Error"),
                httpx.Response(
                    200, json={"status": 0, "docid": 1, "docurl": "http://x"}
                ),
            ]
        )

        with PresentationsAI(api_key=TEST_API_KEY, max_retries=1) as client:
            client.create_from_topic(topic="test", export_type="pptx")

        assert route.call_count == 2

    @respx.mock
    def test_no_retry_on_400(self, respx_mock: respx.MockRouter) -> None:
        """400 should NOT be retried."""
        route = respx_mock.post(f"{BASE}/api/v1/topic/document").mock(
            return_value=httpx.Response(400, json={"error": "Bad request"})
        )

        with (
            PresentationsAI(api_key=TEST_API_KEY, max_retries=3) as client,
            pytest.raises(BadRequestError),
        ):
            client.create_from_topic(topic="test", export_type="pptx")

        assert route.call_count == 1

    @respx.mock
    def test_no_retry_on_401(self, respx_mock: respx.MockRouter) -> None:
        """401 should NOT be retried."""
        route = respx_mock.post(f"{BASE}/api/v1/topic/document").mock(
            return_value=httpx.Response(401, json={"error": "Unauthorized"})
        )

        with (
            PresentationsAI(api_key=TEST_API_KEY, max_retries=3) as client,
            pytest.raises(AuthenticationError),
        ):
            client.create_from_topic(topic="test", export_type="pptx")

        assert route.call_count == 1

    @respx.mock
    def test_exhausts_retries(self, respx_mock: respx.MockRouter) -> None:
        """After max retries, should raise the error."""
        respx_mock.post(f"{BASE}/api/v1/topic/document").mock(
            return_value=httpx.Response(500, text="Server Error")
        )

        with (
            PresentationsAI(api_key=TEST_API_KEY, max_retries=2) as client,
            pytest.raises(InternalServerError),
        ):
            client.create_from_topic(topic="test", export_type="pptx")

    @respx.mock
    def test_zero_retries(self, respx_mock: respx.MockRouter) -> None:
        """max_retries=0 means no retries."""
        route = respx_mock.post(f"{BASE}/api/v1/topic/document").mock(
            return_value=httpx.Response(429, json={"error": "Rate limited"})
        )

        with (
            PresentationsAI(api_key=TEST_API_KEY, max_retries=0) as client,
            pytest.raises(RateLimitError),
        ):
            client.create_from_topic(topic="test", export_type="pptx")

        assert route.call_count == 1
