from unittest.mock import patch, AsyncMock

import pytest

from iis_access._types import NoProviderAvailable, ProviderResolution
from iis_access.provider import resolve_provider, register_free_provider


class TestResolveProvider:
    async def test_returns_local_key_when_env_var_set(self):
        with (
            patch(
                "iis_access.provider.get_auth_context",
                new_callable=AsyncMock,
                return_value=None,
            ),
            patch(
                "iis_access.provider.is_nexus_running",
                new_callable=AsyncMock,
                return_value=False,
            ),
            patch.dict("os.environ", {"OPENAI_API_KEY": "sk-test-123"}),
        ):
            result = await resolve_provider("llm", preferred="openai")

            assert isinstance(result, ProviderResolution)
            assert result.provider == "openai"
            assert result.method == "local_key"
            assert result.api_key == "sk-test-123"
            assert result.endpoint is None

    async def test_returns_free_provider_when_no_keys(self):
        with (
            patch(
                "iis_access.provider.get_auth_context",
                new_callable=AsyncMock,
                return_value=None,
            ),
            patch(
                "iis_access.provider.is_nexus_running",
                new_callable=AsyncMock,
                return_value=False,
            ),
            patch.dict("os.environ", {}, clear=True),
        ):
            result = await resolve_provider("tts")

            assert result.provider == "edge-tts"
            assert result.method == "free"
            assert result.api_key is None
            assert result.credits_estimated == 0

    async def test_raises_no_provider_when_no_options(self):
        with (
            patch(
                "iis_access.provider.get_auth_context",
                new_callable=AsyncMock,
                return_value=None,
            ),
            patch(
                "iis_access.provider.is_nexus_running",
                new_callable=AsyncMock,
                return_value=False,
            ),
            patch.dict("os.environ", {}, clear=True),
        ):
            with pytest.raises(NoProviderAvailable, match="unknown-task"):
                await resolve_provider("unknown-task", preferred="nonexistent")

    async def test_prefers_nexus_for_pro_plan(self):
        from iis_access._types import AuthContext

        ctx = AuthContext(account_id="acc-1", access_token="jwt", plan="pro")

        with (
            patch(
                "iis_access.provider.get_auth_context",
                new_callable=AsyncMock,
                return_value=ctx,
            ),
            patch(
                "iis_access.provider.is_nexus_running",
                new_callable=AsyncMock,
                return_value=True,
            ),
            patch(
                "iis_access.provider._get_nexus_endpoint",
                return_value="http://localhost:9070",
            ),
        ):
            result = await resolve_provider("llm", preferred="openai")

            assert result.method == "nexus"
            assert result.endpoint == "http://localhost:9070"

    async def test_local_key_scan_without_preferred(self):
        """When no preferred provider, scans all known env vars."""
        with (
            patch(
                "iis_access.provider.get_auth_context",
                new_callable=AsyncMock,
                return_value=None,
            ),
            patch(
                "iis_access.provider.is_nexus_running",
                new_callable=AsyncMock,
                return_value=False,
            ),
            patch.dict(
                "os.environ",
                {"ANTHROPIC_API_KEY": "sk-ant-test"},
                clear=True,
            ),
        ):
            result = await resolve_provider("llm")

            assert result.provider == "anthropic"
            assert result.method == "local_key"
            assert result.api_key == "sk-ant-test"


class TestRegisterFreeProvider:
    async def test_register_and_use_free_provider(self):
        register_free_provider("image-gen", "local-sd", check=lambda: True)

        with (
            patch(
                "iis_access.provider.get_auth_context",
                new_callable=AsyncMock,
                return_value=None,
            ),
            patch(
                "iis_access.provider.is_nexus_running",
                new_callable=AsyncMock,
                return_value=False,
            ),
            patch.dict("os.environ", {}, clear=True),
        ):
            result = await resolve_provider("image-gen")

            assert result.provider == "local-sd"
            assert result.method == "free"
