import asyncio
import uuid
import json
from typing import Any, Dict, Union, List
from starlette.responses import Response
from tools.utils import ToolError

class MCPServer:
    def __init__(self):
        self.sessions: Dict[str, asyncio.Queue] = {}
        self.running = True

    def create_session(self) -> str:
        sid = str(uuid.uuid4())
        self.sessions[sid] = asyncio.Queue()
        return sid

    async def send_to_session(self, sid: str, message: Dict[str, Any]):
        if sid in self.sessions:
            await self.sessions[sid].put(json.dumps(message))

    async def handle_request(self, method: str, params: Dict[str, Any], req_id: Any, tool_registry: list) -> Union[Dict[str, Any], Response]:
        if method == "initialize":
            return {
                "protocolVersion": "2024-11-05",
                "capabilities": {"tools": {}},
                "serverInfo": {"name": "MooseCP", "version": "0.4.1"}
            }
        
        if method == "tools/list":
            return {"tools": [t.to_mcp_dict() for t in tool_registry]}
        
        if method == "tools/call":
            name = params.get("name")
            args = params.get("arguments", {})
            
            tool = next((t for t in tool_registry if t.name == name), None)
            if not tool:
                return Response(
                    content=json.dumps({"jsonrpc": "2.0", "id": req_id, "error": {"code": -32601, "message": f"Tool {name} not found"}}),
                    media_type="application/json"
                )
            
            try:
                content = await tool.handler(args)
            except ToolError as e:
                # Convert tool errors into a text response so the LLM can understand and potentially fix the input
                content = [{"type": "text", "text": str(e)}]
            except Exception as e:
                # Catch-all for unexpected crashes to prevent server death
                content = [{"type": "text", "text": f"Unexpected internal error: {str(e)}"}]
            
            return {"content": content}

        return Response(
            content=json.dumps({"jsonrpc": "2.0", "id": req_id, "error": {"code": -32601, "message": f"Method {method} not found"}}),
            media_type="application/json"
        )
