"""Test that all functions degrade gracefully when services are unavailable."""

from unittest.mock import patch, AsyncMock

from aioresponses import aioresponses

from iis_access.auth import get_auth_context
from iis_access.managed_keys import get_managed_key
from iis_access.usage import report_usage
from iis_access.nexus import is_nexus_running


class TestGracefulDegradation:
    async def test_auth_returns_none_without_credentials(self):
        with patch("iis_access.auth.get_credentials", return_value=None):
            result = await get_auth_context()
            assert result is None

    async def test_auth_returns_none_on_network_timeout(self):
        creds = {"accountId": "acc-123", "refreshToken": "iis_rt_test"}

        with (
            patch("iis_access.auth.get_credentials", return_value=creds),
            patch("iis_access.auth._get_keyring", return_value=None),
            patch(
                "iis_access.auth.get_account_url",
                return_value="http://localhost:9060",
            ),
            aioresponses() as mocked,
        ):
            mocked.post(
                "http://localhost:9060/auth/refresh",
                exception=TimeoutError("Connection timed out"),
            )

            result = await get_auth_context()
            assert result is None

    async def test_auth_returns_none_on_server_error(self):
        creds = {"accountId": "acc-123", "refreshToken": "iis_rt_test"}

        with (
            patch("iis_access.auth.get_credentials", return_value=creds),
            patch("iis_access.auth._get_keyring", return_value=None),
            patch(
                "iis_access.auth.get_account_url",
                return_value="http://localhost:9060",
            ),
            aioresponses() as mocked,
        ):
            mocked.post(
                "http://localhost:9060/auth/refresh",
                status=500,
            )

            result = await get_auth_context()
            assert result is None

    async def test_managed_key_returns_none_without_auth(self):
        with patch(
            "iis_access.managed_keys.get_auth_context",
            new_callable=AsyncMock,
            return_value=None,
        ):
            result = await get_managed_key("openai")
            assert result is None

    async def test_usage_silent_on_failure(self):
        """report_usage must never raise, even on complete failure."""
        with patch(
            "iis_access.usage.get_auth_context",
            new_callable=AsyncMock,
            return_value=None,
        ):
            # Should complete without raising
            await report_usage("aria", credits=1.0)

    async def test_nexus_returns_false_when_not_running(self):
        with aioresponses() as mocked:
            mocked.get(
                "http://localhost:9070/health",
                exception=ConnectionError("Connection refused"),
            )

            result = await is_nexus_running()
            assert result is False

    async def test_nexus_returns_false_on_non_200(self):
        with aioresponses() as mocked:
            mocked.get(
                "http://localhost:9070/health",
                status=503,
            )

            result = await is_nexus_running()
            assert result is False
