"""
RAG MCP Tool Provider - ADR-015 模組化架構
==========================================

提供維運手冊 RAG 搜尋工具：
- search_runbook: 語義搜尋維運手冊
- index_documents: 索引文檔 (管理用)
- get_index_stats: 取得索引統計

Phase 13.2 #84 - Runbook RAG Tool

版本: v1.1
建立日期: 2026-03-27 00:00 (台北時區)
更新日期: 2026-03-29 20:40 (台北時區)
建立者: Claude Code
更新者: Claude Code (P1 修復: DI 模式一致性)
"""

import time
import uuid
from pathlib import Path
from typing import TYPE_CHECKING, Any

import structlog

from src.plugins.mcp.interfaces import MCPTool, MCPToolProvider, MCPToolResult

if TYPE_CHECKING:
    from src.services.rag_service import IRAGService

logger = structlog.get_logger(__name__)


class RAGProvider(MCPToolProvider):
    """
    RAG MCP Tool Provider

    提供維運手冊的語義搜尋功能。
    使用 Redis Vector Search + Ollama Embedding。

    支援 DI 注入或 Lazy Load (向後相容):
        # DI 注入 (推薦)
        provider = RAGProvider(rag_service=my_rag_service)

        # Lazy Load (向後相容)
        provider = RAGProvider()
    """

    def __init__(self, rag_service: "IRAGService | None" = None) -> None:
        """
        初始化 Provider

        Args:
            rag_service: RAG Service 實例 (可選，不提供則 lazy load)
        """
        self._rag_service = rag_service

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

    def _get_rag_service(self) -> "IRAGService":
        """
        取得 RAG Service (支援 DI 或 Lazy Load)

        Returns:
            IRAGService: RAG Service 實例
        """
        if self._rag_service is None:
            from src.services.rag_service import get_rag_service
            self._rag_service = get_rag_service()
        return self._rag_service

    async def list_tools(self) -> list[MCPTool]:
        return [
            MCPTool(
                name="search_runbook",
                description="Search runbook documentation with natural language query. Returns relevant sections from ADRs, Skills, and operation guides.",
                input_schema={
                    "type": "object",
                    "properties": {
                        "query": {
                            "type": "string",
                            "description": "Natural language search query (e.g., '如何處理 Pod CrashLoopBackOff')",
                        },
                        "top_k": {
                            "type": "integer",
                            "description": "Number of results to return (default: 5, max: 10)",
                            "default": 5,
                        },
                    },
                    "required": ["query"],
                },
                server_name=self.name,
            ),
            MCPTool(
                name="index_documents",
                description="Index or re-index runbook documents. Admin operation - use when documents are updated.",
                input_schema={
                    "type": "object",
                    "properties": {
                        "force": {
                            "type": "boolean",
                            "description": "Force re-index even if index exists",
                            "default": False,
                        },
                    },
                },
                server_name=self.name,
            ),
            MCPTool(
                name="get_index_stats",
                description="Get RAG index statistics (document count, index status).",
                input_schema={
                    "type": "object",
                    "properties": {},
                },
                server_name=self.name,
            ),
        ]

    async def execute(
        self,
        tool_name: str,
        parameters: dict[str, Any],
    ) -> MCPToolResult:
        """執行 RAG 工具"""
        execution_id = str(uuid.uuid4())
        start_time = time.time()

        try:
            if tool_name == "search_runbook":
                result = await self._search_runbook(parameters)
            elif tool_name == "index_documents":
                result = await self._index_documents(parameters)
            elif tool_name == "get_index_stats":
                result = await self._get_index_stats()
            else:
                return MCPToolResult(
                    success=False,
                    execution_id=execution_id,
                    error=f"Unknown tool: {tool_name}",
                )

            duration = time.time() - start_time

            return MCPToolResult(
                success=True,
                execution_id=execution_id,
                output=result,
                duration=duration,
            )

        except Exception as e:
            logger.error(
                "rag_tool_error",
                tool=tool_name,
                error=str(e),
            )
            return MCPToolResult(
                success=False,
                execution_id=execution_id,
                error=str(e),
                duration=time.time() - start_time,
            )

    async def _search_runbook(self, params: dict) -> dict:
        """
        搜尋維運手冊

        Args:
            params: {query: str, top_k: int}

        Returns:
            dict: 搜尋結果
        """
        query = params.get("query", "")
        top_k = min(params.get("top_k", 5), 10)  # 最多 10 筆

        if not query:
            return {"error": "Query is required", "results": []}

        rag_service = self._get_rag_service()
        results = await rag_service.search(query, top_k)

        logger.info(
            "rag_search_executed",
            query=query[:50],
            results_count=len(results),
        )

        return {
            "query": query,
            "results": results,
            "count": len(results),
        }

    async def _index_documents(self, params: dict) -> dict:
        """
        索引維運手冊

        Args:
            params: {force: bool}

        Returns:
            dict: 索引結果
        """
        force = params.get("force", False)
        rag_service = self._get_rag_service()

        # 如果強制重建，先清除
        if force:
            await rag_service.clear_index()

        # 使用專案根目錄
        # 從當前檔案位置推算: providers/ -> mcp/ -> plugins/ -> src/ -> api/ -> apps/ -> awoooi/
        base_path = Path(__file__).parent.parent.parent.parent.parent.parent.parent

        chunks_indexed = await rag_service.index_documents(base_path)

        logger.info(
            "rag_index_executed",
            chunks=chunks_indexed,
            force=force,
        )

        return {
            "status": "success",
            "chunks_indexed": chunks_indexed,
            "force_rebuild": force,
        }

    async def _get_index_stats(self) -> dict:
        """
        取得索引統計

        Returns:
            dict: 索引統計資訊
        """
        rag_service = self._get_rag_service()
        stats = await rag_service.get_index_stats()

        return stats

    async def health_check(self) -> bool:
        """
        健康檢查

        檢查 Redis 和 Embedding Service 是否可用
        """
        try:
            rag_service = self._get_rag_service()
            stats = await rag_service.get_index_stats()
            return "error" not in stats
        except Exception as e:
            logger.warning("rag_health_check_failed", error=str(e))
            return False

    async def close(self) -> None:
        """關閉 Provider (清理資源)"""
        # RAG Service 使用共享 Redis client，不在此關閉
        self._rag_service = None
        logger.debug("rag_provider_closed")
