from unittest.mock import patch, AsyncMock

import pytest
from aioresponses import aioresponses

from iis_access._types import AuthContext
from iis_access.managed_keys import get_managed_key


def _make_context():
    return AuthContext(
        account_id="acc-123",
        access_token="jwt-token",
        plan="pro",
    )


class TestGetManagedKey:
    async def test_returns_none_when_not_authenticated(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_returns_key_on_success(self):
        with (
            patch(
                "iis_access.managed_keys.get_auth_context",
                new_callable=AsyncMock,
                return_value=_make_context(),
            ),
            patch(
                "iis_access.managed_keys.get_account_url",
                return_value="http://localhost:9060",
            ),
            aioresponses() as mocked,
        ):
            mocked.get(
                "http://localhost:9060/keys/managed/openai",
                payload={"key": "sk-managed-abc"},
            )

            result = await get_managed_key("openai")
            assert result == "sk-managed-abc"

    async def test_returns_cached_key_on_second_call(self):
        with (
            patch(
                "iis_access.managed_keys.get_auth_context",
                new_callable=AsyncMock,
                return_value=_make_context(),
            ),
            patch(
                "iis_access.managed_keys.get_account_url",
                return_value="http://localhost:9060",
            ),
            aioresponses() as mocked,
        ):
            mocked.get(
                "http://localhost:9060/keys/managed/elevenlabs",
                payload={"key": "sk-el-abc"},
            )

            # First call hits API
            result1 = await get_managed_key("elevenlabs")
            assert result1 == "sk-el-abc"

            # Second call uses cache (no mock needed)
            result2 = await get_managed_key("elevenlabs")
            assert result2 == "sk-el-abc"

    async def test_returns_none_on_404(self):
        with (
            patch(
                "iis_access.managed_keys.get_auth_context",
                new_callable=AsyncMock,
                return_value=_make_context(),
            ),
            patch(
                "iis_access.managed_keys.get_account_url",
                return_value="http://localhost:9060",
            ),
            aioresponses() as mocked,
        ):
            mocked.get(
                "http://localhost:9060/keys/managed/unknown",
                status=404,
            )

            result = await get_managed_key("unknown")
            assert result is None

    async def test_returns_none_on_network_error(self):
        with (
            patch(
                "iis_access.managed_keys.get_auth_context",
                new_callable=AsyncMock,
                return_value=_make_context(),
            ),
            patch(
                "iis_access.managed_keys.get_account_url",
                return_value="http://localhost:9060",
            ),
            aioresponses() as mocked,
        ):
            mocked.get(
                "http://localhost:9060/keys/managed/openai",
                exception=ConnectionError("Network unreachable"),
            )

            result = await get_managed_key("openai")
            assert result is None
