"""
P0 DIAGNOSE Routing Tests
==========================
測試 AIRouter DIAGNOSE 路由 + require_local 隔離行為

建立時間: 2026-04-04 (台北時區)
建立者: Claude Code (P0 DIAGNOSE Privacy-First)
2026-04-05 v4.3: Ollama CPU-only 238s 不可用；DIAGNOSE 統一走 NIM (_full_fallback_chain)
"""

import os
os.environ.setdefault("MOCK_MODE", "true")

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


class TestNemotronPerTaskTimeout:
    """Nemotron 支援 per-task timeout"""

    @pytest.mark.asyncio
    async def test_diagnose_uses_diagnose_timeout(self):
        """DIAGNOSE context 應使用 NEMOTRON_DIAGNOSE_TIMEOUT_SECONDS"""
        from src.services.ai_providers.nemotron import NemotronProvider

        provider = NemotronProvider()

        # 建立 mock nvidia provider
        mock_nvidia = MagicMock()
        mock_result = MagicMock()
        mock_result.tool_calls = []
        mock_nvidia.tool_call = AsyncMock(return_value=mock_result)

        with patch.object(provider, '_get_nvidia', return_value=mock_nvidia):
            result = await provider.analyze(
                prompt="測試診斷",
                context={"task_type": "diagnose"},
            )

        assert result.success is True
        mock_nvidia.tool_call.assert_called_once()


class TestLocalFallbackChain:
    """require_local=True 時 privacy 過濾生效，cloud provider 不被呼叫；全部失敗 → REJECT"""

    @pytest.mark.asyncio
    async def test_require_local_skips_cloud_providers(self):
        """require_local=True 時，cloud provider 不被呼叫"""
        import os
        from src.services.ai_router import AIRouterExecutor, AIProviderRegistry
        from src.services.ai_providers.interfaces import AIResult

        registry = AIProviderRegistry()

        # Mock: Ollama 成功
        mock_ollama = AsyncMock()
        mock_ollama.name = "ollama"
        mock_ollama.privacy_level = "local"
        mock_ollama.is_enabled = True
        mock_ollama.capabilities = {"rca", "chat"}
        mock_ollama.analyze = AsyncMock(return_value=AIResult(
            raw_response="本地診斷結果",
            success=True,
            provider="ollama",
        ))
        mock_ollama.health_check = AsyncMock(return_value=True)

        # Mock: Gemini（不應該被呼叫）
        mock_gemini = AsyncMock()
        mock_gemini.name = "gemini"
        mock_gemini.privacy_level = "cloud"
        mock_gemini.is_enabled = True
        mock_gemini.analyze = AsyncMock(return_value=AIResult(
            raw_response="雲端結果",
            success=True,
            provider="gemini",
        ))

        registry._providers = {
            "ollama": mock_ollama,
            "gemini": mock_gemini,
        }

        executor = AIRouterExecutor(registry)

        # 暫時關閉 MOCK_MODE，測試真實執行路徑
        with patch("src.services.ai_router._settings") as mock_settings:
                mock_settings.MOCK_MODE = False
                result = await executor.execute(
                    prompt="診斷這個問題",
                    provider_order=["ollama", "gemini"],
                    require_local=True,
                )

        assert result.success is True
        assert result.provider == "ollama"
        mock_gemini.analyze.assert_not_called()

    @pytest.mark.asyncio
    async def test_require_local_all_fail_returns_reject(self):
        """require_local=True 且所有 local provider 失敗 → 回傳明確錯誤"""
        import os
        from src.services.ai_router import AIRouterExecutor, AIProviderRegistry
        from src.services.ai_providers.interfaces import AIResult

        registry = AIProviderRegistry()

        # Mock: Ollama 失敗
        mock_ollama = AsyncMock()
        mock_ollama.name = "ollama"
        mock_ollama.privacy_level = "local"
        mock_ollama.is_enabled = True
        mock_ollama.capabilities = {"rca", "chat"}
        mock_ollama.analyze = AsyncMock(return_value=AIResult(
            raw_response="",
            success=False,
            provider="ollama",
            error="timeout",
        ))
        mock_ollama.health_check = AsyncMock(return_value=False)

        registry._providers = {
            "ollama": mock_ollama,
        }

        executor = AIRouterExecutor(registry)

        # 暫時關閉 MOCK_MODE + 讓 telegram import 失敗（不影響主流程）
        with patch("src.services.ai_router._settings") as mock_settings:
                mock_settings.MOCK_MODE = False
                result = await executor.execute(
                    prompt="診斷這個問題",
                    provider_order=["ollama"],
                    require_local=True,
                )

        assert result.success is False
        assert result.error == "local_providers_unavailable"


class TestDiagnoseIntentOverride:
    """DIAGNOSE intent 路由設定驗證"""

    def test_diagnose_override_is_ollama(self):
        """_intent_provider_overrides[DIAGNOSE] 應為 OLLAMA（2026-04-29 推翻 A2）

        歷史脈絡：
        - 2026-04-12 ogt: NEMOTRON routing 暫停 — NIM tool_call 無 confidence 欄位
        - 2026-04-16 ogt: 恢復 DIAGNOSE → OPENCLAW_NEMO — None 複雜度路由落入 Rule 6
            → Ollama deepseek-r1:14b CPU 需 238s → timeout → degraded → 全部「待分析」
        - 2026-04-27 Claude Sonnet 4.6 A2: 確立「Ollama 永久排除於 DIAGNOSE chain」

        2026-04-29 推翻 A2 鐵律：
        - 統帥指令: 「主要優先用 111 主機的 Ollama」
        - 統帥鐵律 feedback_ai_autonomous_direction.md: 以本地免費 LLM 為主
        - 統帥鐵律 feedback_ollama_111_only.md: Ollama 唯一主機 = 111
        - 新事實: prod Ollama 111 = M1 Pro Apple Silicon GPU + qwen2.5:7b-instruct
                  VRAM 8.2GB 全載入，實測 hi 0.54s
        - 雲端全死: OpenClaw 500 / Gemini 429 / Claude 404
        - 配套：openclaw.py 注入 task_type="diagnose" → Ollama 用 200s timeout
        """
        from src.services.ai_router import AIRouter, AIProviderEnum
        from src.services.intent_classifier import IntentType

        router = AIRouter()
        override = router._intent_provider_overrides.get(IntentType.DIAGNOSE)
        assert override is AIProviderEnum.OLLAMA, (
            f"統帥鐵律: DIAGNOSE 應為 OLLAMA（本地優先），實際為 {override}"
        )
