"""Tests for alive.llm.registry — provider auto-detection and config loading."""

import json
import os
from pathlib import Path
from unittest.mock import patch

import pytest

from alive.llm.registry import (
    PROVIDERS,
    _auto_detect_provider,
    _inject_config_keys,
    _instantiate,
    _load_config,
    get_provider,
)


# ── _auto_detect_provider ────────────────────────────────────────────────────


class TestAutoDetect:
    def test_detects_claude_from_anthropic_key(self):
        with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-test"}, clear=True):
            assert _auto_detect_provider() == "claude"

    def test_detects_openai_from_key(self):
        with patch.dict(os.environ, {"OPENAI_API_KEY": "sk-test"}, clear=True):
            assert _auto_detect_provider() == "openai"

    def test_detects_deepseek_from_key(self):
        with patch.dict(os.environ, {"DEEPSEEK_API_KEY": "sk-test"}, clear=True):
            assert _auto_detect_provider() == "deepseek"

    def test_falls_back_to_ollama(self):
        with patch.dict(os.environ, {}, clear=True):
            assert _auto_detect_provider() == "ollama"

    def test_claude_takes_priority_over_openai(self):
        env = {"ANTHROPIC_API_KEY": "sk-claude", "OPENAI_API_KEY": "sk-openai"}
        with patch.dict(os.environ, env, clear=True):
            assert _auto_detect_provider() == "claude"


# ── _load_config ─────────────────────────────────────────────────────────────


class TestLoadConfig:
    def test_loads_config_file(self, tmp_path):
        cfg_file = tmp_path / "config.json"
        cfg_file.write_text(json.dumps({"provider": "ollama"}))
        with patch("alive.config.CONFIG_FILE", cfg_file):
            result = _load_config()
            assert result == {"provider": "ollama"}

    def test_returns_empty_when_missing(self, tmp_path):
        cfg_file = tmp_path / "nonexistent.json"
        with patch("alive.config.CONFIG_FILE", cfg_file):
            assert _load_config() == {}

    def test_returns_empty_on_invalid_json(self, tmp_path):
        cfg_file = tmp_path / "config.json"
        cfg_file.write_text("not json")
        with patch("alive.config.CONFIG_FILE", cfg_file):
            assert _load_config() == {}


# ── _inject_config_keys ─────────────────────────────────────────────────────


class TestInjectKeys:
    def test_injects_claude_key(self):
        cfg = {"claude_key": "sk-injected"}
        with patch.dict(os.environ, {}, clear=True):
            _inject_config_keys(cfg)
            assert os.environ.get("ANTHROPIC_API_KEY") == "sk-injected"

    def test_does_not_overwrite_existing_env(self):
        cfg = {"claude_key": "sk-config"}
        with patch.dict(os.environ, {"ANTHROPIC_API_KEY": "sk-env"}, clear=True):
            _inject_config_keys(cfg)
            assert os.environ["ANTHROPIC_API_KEY"] == "sk-env"

    def test_injects_all_keys(self):
        cfg = {
            "claude_key": "sk-c",
            "openai_key": "sk-o",
            "deepseek_key": "sk-d",
        }
        with patch.dict(os.environ, {}, clear=True):
            _inject_config_keys(cfg)
            assert os.environ.get("ANTHROPIC_API_KEY") == "sk-c"
            assert os.environ.get("OPENAI_API_KEY") == "sk-o"
            assert os.environ.get("DEEPSEEK_API_KEY") == "sk-d"


# ── get_provider ─────────────────────────────────────────────────────────────


class TestGetProvider:
    def test_explicit_name_ollama(self, tmp_path):
        cfg_file = tmp_path / "config.json"
        with patch("alive.config.CONFIG_FILE", cfg_file):
            provider = get_provider("ollama")
            assert provider.name == "ollama"

    def test_unknown_provider_raises(self, tmp_path):
        cfg_file = tmp_path / "config.json"
        with patch("alive.config.CONFIG_FILE", cfg_file):
            with pytest.raises(ValueError, match="Unknown provider"):
                get_provider("nonexistent")

    def test_error_message_suggests_config_command(self, tmp_path):
        cfg_file = tmp_path / "config.json"
        with patch("alive.config.CONFIG_FILE", cfg_file):
            with pytest.raises(ValueError, match="alive config --provider"):
                get_provider("bad_provider")

    def test_reads_provider_from_config(self, tmp_path):
        cfg_file = tmp_path / "config.json"
        cfg_file.write_text(json.dumps({"provider": "ollama"}))
        with patch("alive.config.CONFIG_FILE", cfg_file):
            with patch.dict(os.environ, {}, clear=True):
                provider = get_provider()
                assert provider.name == "ollama"

    def test_env_takes_priority_over_config(self, tmp_path):
        cfg_file = tmp_path / "config.json"
        cfg_file.write_text(json.dumps({"provider": "openai"}))
        with patch("alive.config.CONFIG_FILE", cfg_file):
            with patch.dict(os.environ, {"ALIVE_PROVIDER": "ollama"}, clear=True):
                provider = get_provider()
                assert provider.name == "ollama"

    def test_auto_detects_when_no_config(self, tmp_path):
        cfg_file = tmp_path / "config.json"
        with patch("alive.config.CONFIG_FILE", cfg_file):
            with patch.dict(os.environ, {}, clear=True):
                provider = get_provider()
                # Falls back to ollama since no API keys set
                assert provider.name == "ollama"

    def test_config_key_injection_enables_provider(self, tmp_path):
        """Config file API keys should be injected so provider init succeeds."""
        cfg_file = tmp_path / "config.json"
        cfg_file.write_text(json.dumps({"provider": "ollama", "claude_key": "sk-test"}))
        with patch("alive.config.CONFIG_FILE", cfg_file):
            with patch.dict(os.environ, {}, clear=True):
                provider = get_provider()
                assert provider.name == "ollama"


# ── _instantiate ─────────────────────────────────────────────────────────────


class TestInstantiate:
    def test_instantiate_ollama(self):
        p = _instantiate("ollama")
        assert p.name == "ollama"

    def test_instantiate_unknown_raises(self):
        with pytest.raises(KeyError):
            _instantiate("nonexistent")
