#!/usr/bin/env python3
"""
Manual JSON-RPC MCP server implementation to debug stdio issues.
"""

import json
import os
import sys
import time

import requests

from base_server import BaseMCPServer

# Apply startup delay if configured (for Edinburgh deployment)
startup_delay = os.environ.get('STARTUP_DELAY', '0')
try:
    delay = int(startup_delay)
    if delay > 0:
        print(f"Applying startup delay of {delay} seconds...", file=sys.stderr)
        time.sleep(delay)
except ValueError:
    pass

# Check if dynamic mode is enabled
dynamic_mode = os.environ.get('MCP_DYNAMIC_MODE', '').lower() == 'true'
update_method = os.environ.get('MCP_UPDATE_METHOD', '').strip()

# Enable dynamic mode when requested
if dynamic_mode or update_method:
    print(f"Starting Dynamic MCP Server with update method: {update_method or 'websocket'}", file=sys.stderr)
    if os.environ.get('BUNDLE_NAME'):
        print(f"Bundle-specific mode: {os.environ.get('BUNDLE_NAME')}", file=sys.stderr)
    # Run the dynamic server by importing it directly to avoid subprocess issues
    try:
        # Import here to avoid circular dependency
        from dynamic_server import DynamicMCPServer
        dynamic_server = DynamicMCPServer()
        dynamic_server.run()
        sys.exit(0)
    except Exception as e:
        print(f"Failed to start dynamic server: {e}", file=sys.stderr)
        import traceback
        traceback.print_exc()
        sys.exit(1)


class ManualMCPServer(BaseMCPServer):
    """Manual MCP server that handles JSON-RPC directly."""
    
    # Note: __init__ inherited from BaseMCPServer

    def load_tools(self):
        """Load tools from gateway."""
        try:
            gateway_url = os.getenv("GATEWAY_URL", "http://localhost:8000")

            # Use bundle-specific endpoint if bundle is specified
            if self.bundle_name:
                url = f"{gateway_url}/mcp/bundles/{self.bundle_name}/tools"
            else:
                # Use quick endpoint for faster startup
                url = f"{gateway_url}/mcp/tools/quick"

            # Increase timeout and add retry logic
            max_retries = 3
            response = None
            last_error = None
            
            for attempt in range(max_retries):
                try:
                    print(f"Loading tools from: {url} (attempt {attempt + 1}/{max_retries})", file=sys.stderr)
                    response = requests.get(url, timeout=15.0)
                    print(f"Response received: status={response.status_code}", file=sys.stderr)
                    break
                except requests.exceptions.Timeout as e:
                    last_error = e
                    if attempt < max_retries - 1:
                        print(f"Gateway timeout (attempt {attempt + 1}/{max_retries}), retrying...", file=sys.stderr)
                        import time
                        time.sleep(2)  # Brief pause between retries
                        continue
                    print(f"All retries exhausted. Last error: {e}", file=sys.stderr)
                    raise
                except requests.exceptions.RequestException as e:
                    last_error = e
                    print(f"Request error (attempt {attempt + 1}/{max_retries}): {e}", file=sys.stderr)
                    if attempt < max_retries - 1:
                        import time
                        time.sleep(2)
                        continue
                    raise

            if response and response.status_code == 200:
                data = response.json()

                # Handle bundle-specific response format
                if self.bundle_name and "error" in data:
                    # Bundle not found or other error
                    print(f"Bundle error: {data['error']}", file=sys.stderr)
                    return

                # Extract tools from response
                tools_list = data.get("tools", [])

                for tool in tools_list:
                    self.tools.append({
                        "name": tool["name"],
                        "description": tool.get("description", ""),
                        "inputSchema": tool.get("inputSchema", {})
                    })

                # Log bundle information to stderr only
                if self.bundle_name:
                    print(f"Loaded {len(self.tools)} tools from bundle '{self.bundle_name}'", file=sys.stderr)
                else:
                    print(f"Loaded {len(self.tools)} tools (all bundles)", file=sys.stderr)

        except Exception as e:
            print(f"Failed to load tools: {e}", file=sys.stderr)
            print(f"Continuing with empty tools list", file=sys.stderr)
            # Continue with empty tools - MCP server can still function

    def handle_initialize(self, request_id):
        """Handle initialize request."""
        server_name = "coherence-mcp-manual"
        if self.bundle_name:
            server_name = f"coherence-mcp-{self.bundle_name}"

        return {
            "jsonrpc": "2.0",
            "id": request_id,
            "result": {
                "protocolVersion": "2025-06-18",
                "capabilities": {
                    "tools": {"listChanged": False}
                },
                "serverInfo": {
                    "name": server_name,
                    "version": "1.0.0",
                    "bundle": self.bundle_name
                } if self.bundle_name else {
                    "name": server_name,
                    "version": "1.0.0"
                }
            }
        }

    def handle_tools_list(self, request_id):
        """Handle tools/list request."""
        return {
            "jsonrpc": "2.0",
            "id": request_id,
            "result": {
                "tools": self.tools
            }
        }

    def handle_tools_call(self, request_id, params):
        """Handle tools/call request."""
        try:
            tool_name = params.get("name")
            arguments = params.get("arguments", {})

            # Check if tool exists
            if not any(tool["name"] == tool_name for tool in self.tools):
                return {
                    "jsonrpc": "2.0",
                    "id": request_id,
                    "error": {"code": -32602, "message": f"Unknown tool: {tool_name}"}
                }

            # Execute tool via gateway using proper authentication
            import asyncio
            import os

            # Import gateway client (will be in same directory in container)
            import sys
            sys.path.append(os.path.dirname(__file__))
            from gateway_client import GatewayClient

            gateway_url = os.getenv("GATEWAY_URL", "http://localhost:8000")
            jwt_secret = os.getenv("JWT_SECRET", "55c121aa48dc1b79e3c04c805aabd2fe7646253ab6edd1c61894f8146ce1ed17")

            async def execute_tool_async():
                client = GatewayClient(gateway_url, jwt_secret)
                async with client:
                    return await client.execute_tool(tool_name, arguments)

            # Run the async function
            result = asyncio.run(execute_tool_async())

            if result.get("error"):
                response_text = f"Error: {result['error']}"
            else:
                # Format the response for MCP
                response_text = json.dumps(result, indent=2) if isinstance(result, (dict, list)) else str(result)

            return {
                "jsonrpc": "2.0",
                "id": request_id,
                "result": {
                    "content": [
                        {
                            "type": "text",
                            "text": response_text
                        }
                    ]
                }
            }

        except Exception as e:
            return {
                "jsonrpc": "2.0",
                "id": request_id,
                "error": {"code": -32603, "message": str(e)}
            }

    def handle_resources_list(self, request_id):
        """Handle resources/list request."""
        return {
            "jsonrpc": "2.0",
            "id": request_id,
            "result": {
                "resources": []
            }
        }

    def handle_prompts_list(self, request_id):
        """Handle prompts/list request."""
        return {
            "jsonrpc": "2.0",
            "id": request_id,
            "result": {
                "prompts": []
            }
        }

    def run(self):
        """Run the server."""
        # In Docker mode, keep the server running for health checks
        if os.environ.get('MCP_MODE') == 'docker':
            print("MCP Server running in Docker mode - listening on stdin...", file=sys.stderr)
            sys.stderr.flush()
        
        while True:
            try:
                # Read request from stdin
                line = sys.stdin.readline()
                if not line:
                    # In Docker mode, sleep and continue instead of breaking
                    if os.environ.get('MCP_MODE') == 'docker':
                        time.sleep(1)
                        continue
                    break

                request = json.loads(line.strip())
                method = request.get("method")
                request_id = request.get("id")

                if method == "initialize":
                    response = self.handle_initialize(request_id)
                elif method == "tools/list":
                    response = self.handle_tools_list(request_id)
                elif method == "tools/call":
                    response = self.handle_tools_call(request_id, request.get("params", {}))
                elif method == "resources/list":
                    response = self.handle_resources_list(request_id)
                elif method == "prompts/list":
                    response = self.handle_prompts_list(request_id)
                elif method == "notifications/initialized":
                    # This is a notification, no response needed
                    continue
                else:
                    response = {
                        "jsonrpc": "2.0",
                        "id": request_id,
                        "error": {"code": -32601, "message": "Method not found"}
                    }

                # Send response to stdout
                sys.stdout.write(json.dumps(response) + "\n")
                sys.stdout.flush()

            except Exception as e:
                # Send error response
                error_response = {
                    "jsonrpc": "2.0",
                    "id": request.get("id") if 'request' in locals() else None,
                    "error": {"code": -32603, "message": str(e)}
                }
                sys.stdout.write(json.dumps(error_response) + "\n")
                sys.stdout.flush()


if __name__ == "__main__":
    server = ManualMCPServer()
    server.run()
