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

提供 Kubernetes 操作工具：
- kubectl_get: 查詢資源
- kubectl_delete: 刪除 Pod
- kubectl_scale: 調整副本數
- kubectl_restart: 重啟 Deployment

透過 DI 注入 ActionExecutor，不直接 import services。

@see docs/adr/ADR-015-mcp-modular-architecture.md
"""

import uuid
from typing import Any

import structlog

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

logger = structlog.get_logger(__name__)


class K8sProvider(MCPToolProvider):
    """
    Kubernetes MCP Tool Provider

    封裝所有 kubectl 操作，透過 ActionExecutor 執行。
    """

    def __init__(self) -> None:
        # Lazy import to avoid circular dependency
        self._executor = None

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

    def _get_executor(self):
        """Lazy load executor to avoid import at module load time"""
        if self._executor is None:
            from src.services.executor import get_executor
            self._executor = get_executor()
        return self._executor

    async def list_tools(self) -> list[MCPTool]:
        return [
            MCPTool(
                name="kubectl_get",
                description="Query Kubernetes resources (pods, deployments, services)",
                input_schema={
                    "type": "object",
                    "properties": {
                        "resource": {"type": "string", "description": "Resource type: pods, deployments, services"},
                        "namespace": {"type": "string", "description": "Namespace (default: awoooi-prod)"},
                        "name": {"type": "string", "description": "Resource name (optional)"},
                    },
                    "required": ["resource"],
                },
                server_name=self.name,
            ),
            MCPTool(
                name="kubectl_delete",
                description="Delete a Pod (with dry-run validation)",
                input_schema={
                    "type": "object",
                    "properties": {
                        "resource": {"type": "string", "description": "Resource type: pod"},
                        "name": {"type": "string", "description": "Pod name"},
                        "namespace": {"type": "string", "description": "Namespace"},
                    },
                    "required": ["name"],
                },
                server_name=self.name,
            ),
            MCPTool(
                name="kubectl_scale",
                description="Scale a Deployment to N replicas",
                input_schema={
                    "type": "object",
                    "properties": {
                        "deployment": {"type": "string", "description": "Deployment name"},
                        "replicas": {"type": "integer", "description": "Target replica count"},
                        "namespace": {"type": "string", "description": "Namespace"},
                    },
                    "required": ["deployment", "replicas"],
                },
                server_name=self.name,
            ),
            MCPTool(
                name="kubectl_restart",
                description="Restart a Deployment (rollout restart)",
                input_schema={
                    "type": "object",
                    "properties": {
                        "deployment": {"type": "string", "description": "Deployment name"},
                        "namespace": {"type": "string", "description": "Namespace"},
                    },
                    "required": ["deployment"],
                },
                server_name=self.name,
            ),
        ]

    async def execute(
        self,
        tool_name: str,
        parameters: dict[str, Any],
    ) -> MCPToolResult:
        execution_id = str(uuid.uuid4())[:8]
        executor = self._get_executor()

        try:
            if tool_name == "kubectl_get":
                output = await self._kubectl_get(executor, parameters)
            elif tool_name == "kubectl_delete":
                output = await self._kubectl_delete(executor, parameters)
            elif tool_name == "kubectl_scale":
                output = await self._kubectl_scale(executor, parameters)
            elif tool_name == "kubectl_restart":
                output = await self._kubectl_restart(executor, parameters)
            else:
                return MCPToolResult(
                    success=False,
                    execution_id=execution_id,
                    error=f"Unknown tool: {tool_name}",
                )

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

        except Exception as e:
            logger.exception("k8s_provider_error", tool=tool_name, error=str(e))
            return MCPToolResult(
                success=False,
                execution_id=execution_id,
                error=str(e),
            )

    async def _kubectl_get(self, executor, parameters: dict) -> dict:
        namespace = parameters.get("namespace", "awoooi-prod")
        resource = parameters.get("resource", "pods")
        name = parameters.get("name", "")

        cmd = f"kubectl get {resource} {name} -n {namespace} -o json".strip()
        result = await executor.execute_kubectl_command(cmd)

        if result.success and result.k8s_response:
            return result.k8s_response.get("stdout", "")
        return {"error": result.error}

    async def _kubectl_delete(self, executor, parameters: dict) -> dict:
        namespace = parameters.get("namespace", "awoooi-prod")
        resource = parameters.get("resource", "pod")
        name = parameters.get("name", "")

        if not name:
            return {"error": "Missing 'name' parameter"}

        # Dry-run validation
        if resource == "pod":
            dry_run = await executor.validate_pod_exists(name, namespace)
        else:
            dry_run = await executor.validate_deployment_exists(name, namespace)

        if not dry_run.passed:
            return {"error": dry_run.message, "dry_run": False}

        # Execute deletion
        if resource == "pod":
            result = await executor.delete_pod(name, namespace)
        else:
            return {"error": "Direct deployment deletion not supported, use restart"}

        return {
            "success": result.success,
            "message": result.message,
            "duration_ms": result.duration_ms,
        }

    async def _kubectl_scale(self, executor, parameters: dict) -> dict:
        namespace = parameters.get("namespace", "awoooi-prod")
        deployment = parameters.get("deployment", "")
        replicas = parameters.get("replicas", 1)

        if not deployment:
            return {"error": "Missing 'deployment' parameter"}

        cmd = f"kubectl scale deployment/{deployment} --replicas={replicas} -n {namespace}"
        result = await executor.execute_kubectl_command(cmd)

        return {
            "success": result.success,
            "scaled": result.success,
            "replicas": replicas,
            "message": result.message,
        }

    async def _kubectl_restart(self, executor, parameters: dict) -> dict:
        namespace = parameters.get("namespace", "awoooi-prod")
        deployment = parameters.get("deployment", "")

        if not deployment:
            return {"error": "Missing 'deployment' parameter"}

        dry_run = await executor.validate_deployment_exists(deployment, namespace)
        if not dry_run.passed:
            return {"error": dry_run.message, "dry_run": False}

        result = await executor.restart_deployment(deployment, namespace)

        return {
            "success": result.success,
            "restarted": result.success,
            "message": result.message,
            "duration_ms": result.duration_ms,
        }

    async def health_check(self) -> bool:
        """Check if kubectl is accessible"""
        try:
            executor = self._get_executor()
            result = await executor.execute_kubectl_command("kubectl version --client")
            return result.success
        except Exception:
            return False
