#!/usr/bin/env python3
"""
MCP 手掌检测服务器
实现 Model Context Protocol (MCP) 服务器，提供手掌检测功能
"""
import sys
import json
import os
import cv2
import mediapipe as mp
from mediapipe.tasks import python
from mediapipe.tasks.python import vision
from typing import Any, Dict, List, Optional


class MCPServer:
    """MCP 服务器实现，使用 JSON-RPC 2.0 协议通过 stdio 通信"""
    
    def __init__(self):
        self.tools = {}
        self._initialize_detector()
        # 注册工具
        self.register_tool(
            "detect_hand",
            "检测图片中是否存在手掌。输入图片路径，返回检测结果。",
            self._detect_hand
        )
    
    def _initialize_detector(self):
        """初始化 MediaPipe 手部检测器（延迟加载）"""
        self._detector = None
        # 尝试多种方式查找模型文件，提高兼容性
        possible_paths = []
        
        # 方式 1: 环境变量指定的路径（优先级最高）
        env_path = os.environ.get('MCP_HAND_DETECTION_MODEL_PATH')
        if env_path:
            possible_paths.append(env_path)
        
        # 方式 2: 使用 pkg_resources（推荐，适用于已安装的包）
        try:
            import pkg_resources
            path = pkg_resources.resource_filename(
                'mcp_hand_detection', 'data/hand_landmarker.task'
            )
            possible_paths.append(path)
        except:
            pass
        
        # 方式 3: 使用 importlib.resources (Python 3.9+)
        try:
            from importlib import resources
            with resources.path('mcp_hand_detection.data', 'hand_landmarker.task') as path:
                possible_paths.append(str(path))
        except:
            pass
        
        # 方式 4: 相对路径（开发环境）
        possible_paths.append(
            os.path.join(os.path.dirname(__file__), "data", "hand_landmarker.task")
        )
        
        # 查找第一个存在的路径
        self._model_path = None
        for path in possible_paths:
            if os.path.exists(path):
                self._model_path = path
                break
        
        if self._model_path is None:
            # 如果都找不到，使用第一个路径（会在 _get_detector 中报错）
            self._model_path = possible_paths[-1] if possible_paths else None
    
    def _get_detector(self):
        """获取或创建检测器实例"""
        if self._detector is None:
            if not os.path.exists(self._model_path):
                raise FileNotFoundError(
                    f"模型文件不存在: {self._model_path}\n"
                    "请确保模型文件已正确安装，或手动下载到指定位置。"
                )
            
            # 强制使用 CPU 模式，适用于云平台等无 GPU 环境
            base_options = python.BaseOptions(
                model_asset_path=self._model_path,
                delegate=python.BaseOptions.Delegate.CPU
            )
            options = vision.HandLandmarkerOptions(
                base_options=base_options,
                num_hands=1,
                min_hand_detection_confidence=0.5,
                min_hand_presence_confidence=0.5,
                min_tracking_confidence=0.5
            )
            self._detector = vision.HandLandmarker.create_from_options(options)
        return self._detector
    
    def register_tool(self, name: str, description: str, handler):
        """注册工具"""
        self.tools[name] = {
            "name": name,
            "description": description,
            "handler": handler
        }
    
    def _detect_hand(self, image_path: str) -> Dict[str, Any]:
        """
        检测图片中是否存在手掌
        
        Args:
            image_path: 图片文件路径
            
        Returns:
            包含检测结果的字典
        """
        try:
            # 读取图片
            image = cv2.imread(image_path)
            if image is None:
                return {
                    "success": False,
                    "detected": False,
                    "message": f"错误：无法读取文件 '{image_path}'，请检查路径是否正确。"
                }
            
            # 转换颜色通道 BGR to RGB
            image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
            
            # 获取检测器并检测
            detector = self._get_detector()
            mp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=image_rgb)
            detection_result = detector.detect(mp_image)
            
            # 判断是否检测到手掌
            if detection_result.hand_landmarks:
                num_hands = len(detection_result.hand_landmarks)
                return {
                    "success": True,
                    "detected": True,
                    "num_hands": num_hands,
                    "message": f"✅ 检测到手掌！共识别出 {num_hands} 只手。"
                }
            else:
                return {
                    "success": True,
                    "detected": False,
                    "message": "❌ 未在图片中检测到手掌。请确保：\n   1. 图片包含一只清晰、完整的手\n   2. 手掌区域没有被严重遮挡\n   3. 光线均匀"
                }
        except Exception as e:
            return {
                "success": False,
                "detected": False,
                "message": f"检测过程中发生错误: {str(e)}"
            }
    
    def _handle_initialize(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """处理 initialize 请求"""
        return {
            "result": {
                "protocolVersion": "2024-11-05",
                "capabilities": {
                    "tools": {}
                },
                "serverInfo": {
                    "name": "hand-detection-server",
                    "version": "1.0.1"
                }
            }
        }
    
    def _handle_tools_list(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """处理 tools/list 请求"""
        tools = []
        for tool_name, tool_info in self.tools.items():
            tools.append({
                "name": tool_name,
                "description": tool_info["description"],
                "inputSchema": {
                    "type": "object",
                    "properties": {
                        "image_path": {
                            "type": "string",
                            "description": "要检测的图片文件路径"
                        }
                    },
                    "required": ["image_path"]
                }
            })
        return {"result": {"tools": tools}}
    
    def _handle_tools_call(self, params: Dict[str, Any]) -> Dict[str, Any]:
        """处理 tools/call 请求"""
        tool_name = params.get("name")
        arguments = params.get("arguments", {})
        
        if tool_name not in self.tools:
            return {
                "error": {
                    "code": -32601,
                    "message": f"工具 '{tool_name}' 不存在"
                }
            }
        
        try:
            handler = self.tools[tool_name]["handler"]
            result = handler(**arguments)
            return {
                "result": {
                    "content": [
                        {
                            "type": "text",
                            "text": json.dumps(result, ensure_ascii=False, indent=2)
                        }
                    ]
                }
            }
        except Exception as e:
            return {
                "error": {
                    "code": -32603,
                    "message": f"执行工具时发生错误: {str(e)}"
                }
            }
    
    def _handle_request(self, request: Dict[str, Any]) -> Optional[Dict[str, Any]]:
        """处理单个 JSON-RPC 请求"""
        method = request.get("method")
        params = request.get("params", {})
        request_id = request.get("id")
        
        try:
            if method == "initialize":
                result = self._handle_initialize(params)
            elif method == "tools/list":
                result = self._handle_tools_list(params)
            elif method == "tools/call":
                result = self._handle_tools_call(params)
            else:
                result = {
                    "error": {
                        "code": -32601,
                        "message": f"未知方法: {method}"
                    }
                }
        except Exception as e:
            result = {
                "error": {
                    "code": -32603,
                    "message": f"内部错误: {str(e)}"
                }
            }
        
        if request_id is not None:
            return {
                "jsonrpc": "2.0",
                "id": request_id,
                **result
            }
        return None
    
    def run(self):
        """运行服务器，通过 stdio 接收和发送 JSON-RPC 消息"""
        # 读取 stdin 中的 JSON-RPC 请求
        for line in sys.stdin:
            line = line.strip()
            if not line:
                continue
            
            try:
                request = json.loads(line)
                response = self._handle_request(request)
                
                if response:
                    print(json.dumps(response, ensure_ascii=False))
                    sys.stdout.flush()
            except json.JSONDecodeError as e:
                error_response = {
                    "jsonrpc": "2.0",
                    "id": None,
                    "error": {
                        "code": -32700,
                        "message": f"JSON 解析错误: {str(e)}"
                    }
                }
                print(json.dumps(error_response, ensure_ascii=False))
                sys.stdout.flush()
            except Exception as e:
                error_response = {
                    "jsonrpc": "2.0",
                    "id": None,
                    "error": {
                        "code": -32603,
                        "message": f"内部错误: {str(e)}"
                    }
                }
                print(json.dumps(error_response, ensure_ascii=False))
                sys.stdout.flush()


def main():
    """命令行入口点"""
    server = MCPServer()
    server.run()


if __name__ == "__main__":
    main()

