import pytest
from unittest.mock import AsyncMock, patch, PropertyMock

from app.workers.llm_adapter import LLMAdapter, LLMAdapterError


class TestLLMAdapterNoMock:
    """验证LLMAdapter不再返回Mock数据，而是抛出明确错误"""

    @pytest.fixture
    def adapter(self):
        return LLMAdapter()

    @pytest.mark.asyncio
    async def test_enable_llm_false_raises_error(self, adapter):
        """ENABLE_LLM=False时必须抛出LLMAdapterError，而非返回Mock数据"""
        with patch("app.workers.llm_adapter.settings") as mock_settings:
            mock_settings.ENABLE_LLM = False
            mock_settings.DEEPSEEK_API_KEY = "test-key"

            with pytest.raises(LLMAdapterError) as exc_info:
                await adapter.query_brand_citation(
                    keyword="AI搜索",
                    brand_name="测试品牌",
                    brand_aliases=["别名1"],
                )

            error_msg = str(exc_info.value)
            assert "ENABLE_LLM" in error_msg
            assert "未启用" in error_msg

    @pytest.mark.asyncio
    async def test_enable_llm_true_no_api_key_raises_error(self, adapter):
        """ENABLE_LLM=True但无API Key时必须抛出LLMAdapterError"""
        adapter.api_key = None

        with patch("app.workers.llm_adapter.settings") as mock_settings:
            mock_settings.ENABLE_LLM = True

            with pytest.raises(LLMAdapterError) as exc_info:
                await adapter.query_brand_citation(
                    keyword="AI搜索",
                    brand_name="测试品牌",
                    brand_aliases=[],
                )

            error_msg = str(exc_info.value)
            assert "API Key" in error_msg or "DEEPSEEK_API_KEY" in error_msg

    @pytest.mark.asyncio
    async def test_enable_llm_true_with_key_calls_api(self, adapter):
        """ENABLE_LLM=True且有Key时正常调用API"""
        mock_response = {
            "cited": True,
            "position": 1,
            "citation_text": "测试引用",
            "sentiment": "positive",
            "confidence": 0.95,
        }

        with patch("app.workers.llm_adapter.settings") as mock_settings:
            mock_settings.ENABLE_LLM = True
            mock_settings.OPENAI_API_KEY = None
            mock_settings.DEEPSEEK_API_KEY = "sk-test-key"

            with patch.object(
                adapter, "_call_deepseek", new_callable=AsyncMock
            ) as mock_call:
                mock_call.return_value = mock_response

                result = await adapter.query_brand_citation(
                    keyword="AI搜索",
                    brand_name="测试品牌",
                    brand_aliases=[],
                )

                assert result.cited is True
                assert result.position == 1
                assert result.sentiment == "positive"

    def test_get_mock_result_method_removed(self):
        """_get_mock_result方法必须已被删除"""
        assert not hasattr(LLMAdapter, "_get_mock_result"), (
            "_get_mock_result方法仍然存在，必须删除"
        )

    @pytest.mark.asyncio
    async def test_error_message_user_friendly(self, adapter):
        """错误信息必须对用户友好，包含配置指引"""
        with patch("app.workers.llm_adapter.settings") as mock_settings:
            mock_settings.ENABLE_LLM = False
            mock_settings.DEEPSEEK_API_KEY = "test-key"

            with pytest.raises(LLMAdapterError) as exc_info:
                await adapter.query_brand_citation(
                    keyword="AI搜索",
                    brand_name="测试品牌",
                    brand_aliases=[],
                )

            error_msg = str(exc_info.value)
            assert "ENABLE_LLM=True" in error_msg
            assert "DEEPSEEK_API_KEY" in error_msg

    @pytest.mark.asyncio
    async def test_no_api_key_error_message_user_friendly(self, adapter):
        """无API Key时错误信息必须包含配置指引"""
        adapter.api_key = None

        with patch("app.workers.llm_adapter.settings") as mock_settings:
            mock_settings.ENABLE_LLM = True

            with pytest.raises(LLMAdapterError) as exc_info:
                await adapter.query_brand_citation(
                    keyword="AI搜索",
                    brand_name="测试品牌",
                    brand_aliases=[],
                )

            error_msg = str(exc_info.value)
            assert "DEEPSEEK_API_KEY" in error_msg
