"""
Nemotron Tool Calling Provider - Phase 24 ADR-052
==================================================
封裝 NVIDIA Nemotron Tool Calling 能力，供 AIRouter 路由。

搬移自: openclaw.py _call_nemotron_tools (L1623-1785)
特性: K8s Tool Calling，83.3% 精準度，HITL 高風險保護

架構鐵律: AIRouter → NemotronProvider → NvidiaProvider → NVIDIA NIM

2026-04-02 Claude Code: Phase 24 B3 NemotronProvider 抽取
"""

from __future__ import annotations

import asyncio
import time
from typing import Any

import structlog

from src.core.config import get_settings
from src.services.ai_providers.interfaces import AIProvider, AIResult, is_provider_enabled_by_env

logger = structlog.get_logger(__name__)
settings = get_settings()

# 預定義 K8s Tool Definitions (搬移自 openclaw.py _call_nemotron_tools)
_K8S_TOOLS: list[dict] = [
    {
        "type": "function",
        "function": {
            "name": "restart_deployment",
            "description": "重啟 Deployment (rollout restart)",
            "parameters": {
                "type": "object",
                "properties": {
                    "deployment_name": {"type": "string"},
                    "namespace": {"type": "string", "default": "awoooi-prod"},
                },
                "required": ["deployment_name"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "scale_deployment",
            "description": "調整 Deployment 副本數",
            "parameters": {
                "type": "object",
                "properties": {
                    "deployment_name": {"type": "string"},
                    "replicas": {"type": "integer"},
                    "namespace": {"type": "string", "default": "awoooi-prod"},
                },
                "required": ["deployment_name", "replicas"],
            },
        },
    },
    {
        "type": "function",
        "function": {
            "name": "delete_pod",
            "description": "刪除 Pod (強制重建)",
            "parameters": {
                "type": "object",
                "properties": {
                    "pod_name": {"type": "string"},
                    "namespace": {"type": "string", "default": "awoooi-prod"},
                },
                "required": ["pod_name"],
            },
        },
    },
]


class NemotronProvider:
    """
    NVIDIA Nemotron Tool Calling Provider

    privacy_level: cloud (NIM 是雲端 GPU，首席架構師 Q2 裁示)
    capabilities: tool_calling (K8s 操作決策專用)

    呼叫路徑:
    AIRouter → NemotronProvider → NvidiaProvider (ADR-036) → NVIDIA NIM API
    """

    def __init__(self) -> None:
        # NvidiaProvider 採用懶加載，避免 import-time 副作用
        self._nvidia: Any | None = None

    def _get_nvidia(self) -> Any:
        if self._nvidia is None:
            from src.services.nvidia_provider import get_nvidia_provider
            self._nvidia = get_nvidia_provider()
        return self._nvidia

    @property
    def name(self) -> str:
        return "nemotron"

    @property
    def is_enabled(self) -> bool:
        return is_provider_enabled_by_env("nemotron")

    @property
    def capabilities(self) -> set[str]:
        return {"tool_calling"}

    @property
    def privacy_level(self) -> str:
        # 2026-04-04 ogt: Phase 25 首席架構師裁示 — NIM 部署在 192.168.0.188（內網 GPU）
        # 非 NVIDIA 官方雲端 API，屬 local infra，可納入 DIAGNOSE 隱私邊界
        # 原標注 cloud 錯誤（Q2 裁示前的預設），此次更正
        return "local"

    async def analyze(
        self,
        prompt: str,
        context: dict[str, Any] | None = None,
    ) -> AIResult:
        """
        執行 K8s Tool Calling 分析

        context 結構:
          - incident_id: str (Incident ID)
          - reasoning: str (OpenClaw 推理結果)
          - target_resource: str (目標資源名稱)
          - suggested_action: str (OpenClaw 建議操作)
          - namespace: str (K8s namespace，預設 awoooi-prod)

        回傳 AIResult.raw_response 為 JSON 字串:
          {"tools": [...], "validation": str, "latency_ms": float}
        """
        import json as _json

        start = time.perf_counter()
        context = context or {}

        # 從 context 取出欄位，fallback 到 prompt
        incident_id = context.get("incident_id", "UNKNOWN")
        reasoning = context.get("reasoning", prompt)
        target_resource = context.get("target_resource", "unknown")
        suggested_action = context.get("suggested_action", prompt)
        namespace = context.get("namespace", "awoooi-prod")

        # 2026-04-09 Claude Code: 明確指示 deployment_name，防止 Nemotron 填 placeholder
        tool_prompt = f"""根據以下 AI 分析結果，生成對應的 kubectl 操作指令：

## Incident 上下文
- Incident ID: {incident_id}
- 目標資源 (deployment_name): {target_resource}
- Namespace: {namespace}

## OpenClaw 分析
- 建議操作: {suggested_action}
- 推理過程: {reasoning[:500]}

## 你的任務
使用提供的工具生成 kubectl 操作。
**重要**: deployment_name 必須填入 "{target_resource}"，不可使用 placeholder。
"""

        try:
            # 2026-04-04 ogt: Phase 25 P0 — 根據 task_type 選擇 timeout
            # DIAGNOSE 用較短 timeout（30s），避免拖累整體 AutoRepair 流程
            task_type = context.get("task_type", "")
            if task_type == "diagnose":
                timeout = getattr(settings, "NEMOTRON_DIAGNOSE_TIMEOUT_SECONDS", 30)
            else:
                timeout = getattr(settings, "NEMOTRON_TIMEOUT_SECONDS", 45)
            nvidia = self._get_nvidia()

            # 2026-04-05 Claude Code: I2 修正 — 補上 system prompt (NIM 標準 message format)
            # NIM API 要求 system role 先定義模型角色，否則 tool calling 品質下降
            result = await asyncio.wait_for(
                nvidia.tool_call(
                    messages=[
                        {
                            "role": "system",
                            "content": (
                                "你是 Kubernetes 操作專家。根據 AI 診斷結果，"
                                "使用提供的工具生成精確的 kubectl 操作指令。"
                                "優先選擇最安全、最小影響範圍的操作。"
                            ),
                        },
                        {"role": "user", "content": tool_prompt},
                    ],
                    tools=_K8S_TOOLS,
                ),
                timeout=timeout,
            )

            latency_ms = (time.perf_counter() - start) * 1000

            # 解析 Tool Calling 結果 (搬移自 openclaw.py L1734-1756)
            tools: list[dict] = []
            validation_passed = True

            if result and hasattr(result, "tool_calls") and result.tool_calls:
                for tc in result.tool_calls:
                    tool_entry = {
                        "tool": tc.tool_name if hasattr(tc, "tool_name") else str(tc.get("name", "unknown")),
                        "args": tc.arguments if hasattr(tc, "arguments") else tc.get("arguments", {}),
                        "valid": tc.valid if hasattr(tc, "valid") else True,
                    }
                    tools.append(tool_entry)
                    if not tool_entry["valid"]:
                        validation_passed = False
            elif result and isinstance(result, dict) and result.get("tool_calls"):
                for tc in result["tool_calls"]:
                    tool_entry = {
                        "tool": tc.get("name", "unknown"),
                        "args": tc.get("arguments", {}),
                        "valid": True,
                    }
                    tools.append(tool_entry)

            validation_status = "✅ 驗證通過" if validation_passed and tools else "❌ 驗證失敗"

            # 2026-04-09 Claude Sonnet 4.6: 記錄 tool calling 使用的模型和後端
            from src.services.nvidia_provider import OllamaToolProvider
            if isinstance(nvidia, OllamaToolProvider):
                tool_model = settings.OLLAMA_TOOL_MODEL  # e.g. "llama3.1:8b"
                tool_backend = "Ollama 本機"
            else:
                tool_model = "nemotron-mini-4b-instruct"
                tool_backend = "NVIDIA 雲端"

            payload = {
                "tools": tools,
                "validation": validation_status,
                "latency_ms": latency_ms,
                "tool_model": tool_model,
                "tool_backend": tool_backend,
            }

            logger.info(
                "nemotron_provider_success",
                incident_id=incident_id,
                tool_count=len(tools),
                validation=validation_status,
                latency_ms=round(latency_ms, 1),
            )

            return AIResult(
                raw_response=_json.dumps(payload, ensure_ascii=False),
                success=True,
                provider=self.name,
                latency_ms=latency_ms,
            )

        except asyncio.TimeoutError:
            latency_ms = (time.perf_counter() - start) * 1000
            # 2026-04-04 ogt: I1 修正 — 使用實際套用的 timeout（依 task_type 選擇）
            logger.warning(
                "nemotron_provider_timeout",
                incident_id=incident_id,
                timeout_seconds=timeout,
                task_type=task_type,
                latency_ms=round(latency_ms, 1),
            )
            return AIResult(
                raw_response="",
                success=False,
                provider=self.name,
                latency_ms=latency_ms,
                error=f"Tool calling timeout after {timeout}s",
            )

        except Exception as e:
            latency_ms = (time.perf_counter() - start) * 1000
            logger.error(
                "nemotron_provider_error",
                incident_id=incident_id,
                error=str(e),
                latency_ms=round(latency_ms, 1),
            )
            return AIResult(
                raw_response="",
                success=False,
                provider=self.name,
                latency_ms=latency_ms,
                error=str(e),
            )

    async def health_check(self) -> bool:
        """健康檢查：嘗試初始化 NvidiaProvider"""
        try:
            nvidia = self._get_nvidia()
            # NvidiaProvider 有 health_check 就用，沒有就只驗證能實例化
            if hasattr(nvidia, "health_check"):
                return await nvidia.health_check()
            return True
        except Exception:
            return False
