"""Tests for provider wiring — multi-env, endpoint-grouped custom, registry."""

from __future__ import annotations

import os
from unittest.mock import MagicMock, patch

import pytest
from icarus.config.app_config import _get_provider_kwargs
from icarus.config.model_config import (
    PROVIDER_MULTI_ENV,
    PROVIDERS_WITH_ENDPOINTS,
    _collect_env_vars,
    _has_env_credentials,
    clear_caches,
    get_provider_registry,
    has_provider_credentials,
    ModelConfig,
)


@pytest.fixture(autouse=True)
def _clear(monkeypatch):
    clear_caches()
    for vars_list in PROVIDER_MULTI_ENV.values():
        for var in vars_list:
            monkeypatch.delenv(var["name"], raising=False)
    yield
    clear_caches()


class TestProviderMultiEnv:
    def test_vertex_ai_has_three_env_vars(self):
        assert "google_vertexai" in PROVIDER_MULTI_ENV
        names = [v["name"] for v in PROVIDER_MULTI_ENV["google_vertexai"]]
        assert "GOOGLE_APPLICATION_CREDENTIALS" in names
        assert "GOOGLE_CLOUD_PROJECT" in names

    def test_aws_has_two_env_vars(self):
        assert "bedrock_converse" in PROVIDER_MULTI_ENV
        names = [v["name"] for v in PROVIDER_MULTI_ENV["bedrock_converse"]]
        assert "AWS_BEARER_TOKEN_BEDROCK" in names
        assert "AWS_DEFAULT_REGION" in names


class TestCollectEnvVars:
    def test_multi_env_provider_returns_all_vars(self, monkeypatch):
        monkeypatch.setenv("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/sa.json")
        monkeypatch.setenv("GOOGLE_CLOUD_PROJECT", "my-project")
        result = _collect_env_vars("google_vertexai", {})
        names = [e["name"] for e in result]
        assert "GOOGLE_APPLICATION_CREDENTIALS" in names
        assert "GOOGLE_CLOUD_PROJECT" in names

    def test_multi_env_partial_set(self, monkeypatch):
        monkeypatch.setenv("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/sa.json")
        monkeypatch.delenv("GOOGLE_CLOUD_PROJECT", raising=False)
        result = _collect_env_vars("google_vertexai", {})
        by_name = {e["name"]: e for e in result}
        assert by_name["GOOGLE_APPLICATION_CREDENTIALS"]["is_set"] is True
        assert by_name["GOOGLE_CLOUD_PROJECT"]["is_set"] is False

    def test_multi_env_has_is_file_path(self, monkeypatch):
        result = _collect_env_vars("google_vertexai", {})
        by_name = {e["name"]: e for e in result}
        assert by_name["GOOGLE_APPLICATION_CREDENTIALS"]["is_file_path"] is True
        assert by_name["GOOGLE_CLOUD_PROJECT"].get("is_file_path", False) is False

    def test_aws_env_vars_collected(self, monkeypatch):
        monkeypatch.setenv("AWS_BEARER_TOKEN_BEDROCK", "br-key-123")
        monkeypatch.setenv("AWS_DEFAULT_REGION", "us-east-1")
        result = _collect_env_vars("bedrock_converse", {})
        names = [e["name"] for e in result]
        assert len(names) == 2

    def test_single_env_provider_unchanged(self, monkeypatch):
        monkeypatch.setenv("ANTHROPIC_API_KEY", "sk-test")
        result = _collect_env_vars("anthropic", {})
        assert len(result) == 1
        assert result[0]["name"] == "ANTHROPIC_API_KEY"


class TestProvidersWithEndpoints:
    def test_custom_is_endpoint_grouped(self):
        assert "custom" in PROVIDERS_WITH_ENDPOINTS

    def test_azure_still_endpoint_grouped(self):
        assert "azure_ai" in PROVIDERS_WITH_ENDPOINTS


class TestProviderRegistry:
    @patch("icarus.config.model_config.ModelConfig.load")
    @patch("icarus.config.model_config._get_provider_profile_modules", return_value=[])
    @patch("icarus.config.ollama.discover_ollama_models", return_value=[])
    @patch("icarus.config.ollama.get_ollama_base_url", return_value="http://localhost:11434")
    def test_aws_appears_in_registry(self, _url, _disco, _profiles, mock_load):
        mock_load.return_value = MagicMock(
            providers={}, get_base_url=MagicMock(return_value=None),
            get_api_key_env=MagicMock(return_value=None),
        )
        registry = get_provider_registry()
        names = [p["name"] for p in registry]
        assert "bedrock_converse" in names

    @patch("icarus.config.model_config.ModelConfig.load")
    @patch("icarus.config.model_config._get_provider_profile_modules", return_value=[])
    @patch("icarus.config.ollama.discover_ollama_models", return_value=[])
    @patch("icarus.config.ollama.get_ollama_base_url", return_value="http://localhost:11434")
    def test_aws_has_two_env_vars_in_registry(self, _url, _disco, _profiles, mock_load):
        mock_load.return_value = MagicMock(
            providers={}, get_base_url=MagicMock(return_value=None),
            get_api_key_env=MagicMock(return_value=None),
        )
        registry = get_provider_registry()
        aws = next(p for p in registry if p["name"] == "bedrock_converse")
        assert len(aws["env_vars"]) == 2

    @patch("icarus.config.model_config.ModelConfig.load")
    @patch("icarus.config.model_config._get_provider_profile_modules", return_value=[])
    @patch("icarus.config.ollama.discover_ollama_models", return_value=[])
    @patch("icarus.config.ollama.get_ollama_base_url", return_value="http://localhost:11434")
    def test_custom_always_in_registry(self, _url, _disco, _profiles, mock_load):
        mock_load.return_value = MagicMock(
            providers={}, get_base_url=MagicMock(return_value=None),
            get_api_key_env=MagicMock(return_value=None),
        )
        registry = get_provider_registry()
        names = [p["name"] for p in registry]
        assert "custom" in names
        custom = next(p for p in registry if p["name"] == "custom")
        assert custom["has_endpoints"] is True


class TestMultiEnvCredentials:
    def test_vertex_ai_credentialed_with_both(self, monkeypatch):
        monkeypatch.setenv("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/sa.json")
        monkeypatch.setenv("GOOGLE_CLOUD_PROJECT", "my-project")
        assert _has_env_credentials("google_vertexai") is True

    def test_vertex_ai_credentialed_with_adc(self, monkeypatch):
        """ADC users only set GOOGLE_CLOUD_PROJECT — still credentialed."""
        monkeypatch.delenv("GOOGLE_APPLICATION_CREDENTIALS", raising=False)
        monkeypatch.setenv("GOOGLE_CLOUD_PROJECT", "my-project")
        assert _has_env_credentials("google_vertexai") is True

    def test_vertex_ai_not_credentialed_no_project(self, monkeypatch):
        monkeypatch.setenv("GOOGLE_APPLICATION_CREDENTIALS", "/path/to/sa.json")
        monkeypatch.delenv("GOOGLE_CLOUD_PROJECT", raising=False)
        assert _has_env_credentials("google_vertexai") is False

    def test_vertex_ai_not_credentialed_when_empty(self, monkeypatch):
        monkeypatch.delenv("GOOGLE_APPLICATION_CREDENTIALS", raising=False)
        monkeypatch.delenv("GOOGLE_CLOUD_PROJECT", raising=False)
        assert _has_env_credentials("google_vertexai") is False

    def test_aws_credentialed_when_api_key_set(self, monkeypatch):
        monkeypatch.setenv("AWS_BEARER_TOKEN_BEDROCK", "br-key-123")
        assert _has_env_credentials("bedrock_converse") is True

    def test_aws_not_credentialed_when_empty(self, monkeypatch):
        monkeypatch.delenv("AWS_BEARER_TOKEN_BEDROCK", raising=False)
        assert _has_env_credentials("bedrock_converse") is False


class TestCustomProviderKwargs:
    @patch("icarus.config.model_config.ModelConfig.load")
    def test_custom_provider_injects_base_url_from_endpoint(self, mock_load):
        """Custom provider models should get base_url from their endpoint param."""
        mock_load.return_value = MagicMock(
            providers={"custom": {
                "models": ["llama3"],
                "params": {"llama3": {"endpoint": "http://localhost:8000"}},
            }},
            get_base_url=MagicMock(return_value=None),
            get_api_key_env=MagicMock(return_value=None),
            get_class_path=MagicMock(return_value=None),
            get_kwargs=MagicMock(return_value={"endpoint": "http://localhost:8000"}),
        )
        kwargs, class_path = _get_provider_kwargs("custom", model_name="llama3")
        assert kwargs.get("base_url") == "http://localhost:8000"
        assert "endpoint" not in kwargs  # Converted to base_url
