#!/usr/bin/env python
#
# Copyright(C) 2025-2026 Advanced Micro Devices, Inc. All rights reserved.
# SPDX-License-Identifier: MIT

"""
GAIA MCP Bridge - HTTP Native Implementation
No WebSockets, just clean HTTP + JSON-RPC for maximum compatibility
"""

import io
import json
import os
import shutil
import sys
import tempfile
from http.server import BaseHTTPRequestHandler, HTTPServer
from pathlib import Path
from typing import Any, Dict
from urllib.parse import urlparse

from python_multipart.multipart import MultipartParser, parse_options_header

# Add GAIA to path
sys.path.insert(
    0, os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
)

from gaia.agents.blender.agent import BlenderAgent
from gaia.llm import create_client
from gaia.logger import get_logger

logger = get_logger(__name__)

# Global verbose flag for request logging
VERBOSE = False


class MultipartCollector:
    def __init__(self):
        self.fields = {}
        self.files = {}
        self._headers = []
        self._name = None
        self._filename = None
        self._buffer = None

    def _parse_cd(self, value: str):
        name = None
        filename = None
        try:
            parts = [p.strip() for p in value.split(";")]
            for p in parts:
                pl = p.lower()
                if pl.startswith("name="):
                    name = p.split("=", 1)[1].strip().strip('"')
                elif pl.startswith("filename="):
                    filename = p.split("=", 1)[1].strip().strip('"')
        except Exception:
            pass
        return name, filename

    def on_part_begin(self):
        self._headers = []
        self._name = None
        self._filename = None
        self._buffer = io.BytesIO()

    def on_header_field(self, data: bytes, start: int, end: int):
        field = data[start:end].decode("latin-1")
        self._headers.append([field, ""])

    def on_header_value(self, data: bytes, start: int, end: int):
        if self._headers:
            self._headers[-1][1] += data[start:end].decode("latin-1")

    def on_headers_finished(self):
        for k, v in self._headers:
            if k.lower() == "content-disposition":
                name, filename = self._parse_cd(v)
                self._name = name
                self._filename = filename

    def on_part_data(self, data: bytes, start: int, end: int):
        if self._buffer is not None:
            self._buffer.write(data[start:end])

    def on_part_end(self):
        if self._name is None:
            self._buffer = None
            return
        if self._filename:
            self.files[self._name] = {
                "file_name": self._filename,
                "file_object": self._buffer,
            }
        else:
            self.fields[self._name] = self._buffer.getvalue()
        self._buffer = None

    def callbacks(self):
        return {
            "on_part_begin": self.on_part_begin,
            "on_header_field": self.on_header_field,
            "on_header_value": self.on_header_value,
            "on_headers_finished": self.on_headers_finished,
            "on_part_data": self.on_part_data,
            "on_part_end": self.on_part_end,
        }


class GAIAMCPBridge:
    """HTTP-native MCP Bridge for GAIA - no WebSockets needed!"""

    def __init__(
        self,
        host: str = "localhost",
        port: int = 8765,
        base_url: str = None,
        verbose: bool = False,
    ):
        self.host = host
        self.port = port
        self.base_url = base_url or "http://localhost:8000/api/v1"
        self.agents = {}
        self.tools = {}
        self.llm_client = None
        self.verbose = verbose
        global VERBOSE
        VERBOSE = verbose

        # Initialize on creation
        self._initialize_agents()
        self._register_tools()

    def _initialize_agents(self):
        """Initialize all GAIA agents."""
        try:
            # LLM agent
            self.agents["llm"] = {
                "module": "gaia.apps.llm.app",
                "function": "main",
                "description": "Direct LLM interaction",
                "capabilities": ["query", "stream", "model_selection"],
            }

            # Chat agent
            self.agents["chat"] = {
                "module": "gaia.chat.app",
                "function": "main",
                "description": "Interactive chat",
                "capabilities": ["conversation", "history", "context_management"],
            }

            # Blender agent
            try:
                self.agents["blender"] = {
                    "class": BlenderAgent,
                    "description": "3D content creation",
                    "capabilities": ["3d_modeling", "scene_manipulation", "rendering"],
                }
            except ImportError:
                logger.warning("Blender agent not available")
            # Summarize agent
            try:
                from gaia.agents.summarize.agent import SummarizerAgent

                self.agents["summarize"] = {
                    "class": SummarizerAgent,
                    "description": "Text/document summarization",
                    "capabilities": ["summarize", "pdf", "email", "transcript"],
                    "init_params": {},
                }
                logger.info("✅ Summarize agent registered")
            except ImportError as e:
                logger.warning(f"Summarize agent not available: {e}")
            # Jira agent - THE KEY ADDITION
            try:
                from gaia.agents.jira.agent import JiraAgent

                self.agents["jira"] = {
                    "class": JiraAgent,
                    "description": "Natural language Jira orchestration",
                    "capabilities": ["search", "create", "update", "bulk_operations"],
                    "init_params": {
                        "model_id": "Qwen3-Coder-30B-A3B-Instruct-GGUF",
                        "silent_mode": True,
                        "debug": False,
                    },
                }
                logger.info("✅ Jira agent registered")
            except ImportError as e:
                logger.warning(f"Jira agent not available: {e}")

            logger.info(f"Initialized {len(self.agents)} agents")

        except Exception as e:
            logger.error(f"Agent initialization error: {e}")

    def _register_tools(self):
        """Register available tools."""
        # Load from mcp.json if available
        try:
            mcp_config_path = os.path.join(os.path.dirname(__file__), "mcp.json")
            if os.path.exists(mcp_config_path):
                with open(mcp_config_path, "r") as f:
                    config = json.load(f)
                    tools_config = config.get("tools", {})
                    # Convert tool config to proper MCP format with name field
                    self.tools = {}
                    for tool_name, tool_data in tools_config.items():
                        self.tools[tool_name] = {
                            "name": tool_name,
                            "description": tool_data.get("description", ""),
                            "servers": tool_data.get("servers", []),
                            "parameters": tool_data.get("parameters", {}),
                        }
                    logger.info(f"Loaded {len(self.tools)} tools from mcp.json")
        except Exception as e:
            logger.warning(f"Could not load mcp.json: {e}")

        # Ensure core tools are registered
        if "gaia.jira" not in self.tools:
            self.tools["gaia.jira"] = {
                "name": "gaia.jira",
                "description": "Natural language Jira operations",
                "inputSchema": {
                    "type": "object",
                    "properties": {
                        "query": {"type": "string"},
                        "operation": {
                            "type": "string",
                            "enum": ["query", "create", "update"],
                        },
                    },
                },
            }

        if "gaia.chat" not in self.tools:
            self.tools["gaia.chat"] = {
                "name": "gaia.chat",
                "description": "Conversational chat with context",
                "inputSchema": {
                    "type": "object",
                    "properties": {"query": {"type": "string"}},
                },
            }

        if "gaia.query" not in self.tools:
            self.tools["gaia.query"] = {
                "name": "gaia.query",
                "description": "Direct LLM queries (no conversation context)",
                "inputSchema": {
                    "type": "object",
                    "properties": {"query": {"type": "string"}},
                },
            }

    def execute_tool(self, tool_name: str, arguments: Dict[str, Any]) -> Dict[str, Any]:
        """Execute a tool and return results."""
        try:
            if tool_name == "gaia.jira":
                return self._execute_jira(arguments)
            elif tool_name == "gaia.query":
                return self._execute_query(arguments)
            elif tool_name == "gaia.chat":
                return self._execute_chat(arguments)
            elif tool_name == "gaia.blender.create":
                return self._execute_blender(arguments)
            elif tool_name == "gaia.summarize":
                return self._execute_summarize(arguments)
            else:
                return {"error": f"Tool not implemented: {tool_name}"}
        except Exception as e:
            logger.error(f"Tool execution error: {e}")
            return {"error": str(e)}

    def _execute_jira(self, args: Dict[str, Any]) -> Dict[str, Any]:
        """Execute Jira operations."""
        query = args.get("query", "")

        # Get or create agent
        agent_config = self.agents.get("jira")
        if not agent_config:
            return {"error": "Jira agent not available"}

        # Lazy initialization
        if "instance" not in agent_config:
            agent_class = agent_config["class"]
            init_params = agent_config.get("init_params", {})
            agent_config["instance"] = agent_class(**init_params)

            # Initialize Jira config discovery
            try:
                config = agent_config["instance"].initialize()
                logger.info(
                    f"Jira initialized: {len(config.get('projects', []))} projects found"
                )
            except Exception as e:
                logger.warning(f"Jira config discovery failed: {e}")

        agent = agent_config["instance"]

        # Execute query
        result = agent.process_query(query, trace=False)

        return {
            "success": True,
            "result": result.get("final_answer", ""),
            "steps_taken": result.get("steps_taken", 0),
            "conversation": result.get("conversation", []),
        }

    def _execute_query(self, args: Dict[str, Any]) -> Dict[str, Any]:
        """Execute LLM query."""
        if not self.llm_client:
            self.llm_client = create_client("lemonade", base_url=self.base_url)

        response = self.llm_client.generate(
            prompt=args.get("query", ""),
            model=args.get("model"),
            max_tokens=args.get("max_tokens", 500),
        )

        return {"success": True, "result": response}

    def _execute_chat(self, args: Dict[str, Any]) -> Dict[str, Any]:
        """Execute chat interaction with conversation context."""
        try:
            from gaia.chat.sdk import ChatConfig, ChatSDK

            # Initialize chat SDK if not already done
            if not hasattr(self, "chat_sdk"):
                # ChatSDK uses the global LLM configuration, not a base_url
                config = ChatConfig()
                self.chat_sdk = ChatSDK(config=config)

            # Get the query
            query = args.get("query", "")

            # Send message and get response
            chat_response = self.chat_sdk.send(query)

            # Extract the text response
            if hasattr(chat_response, "text"):
                response = chat_response.text
            elif hasattr(chat_response, "content"):
                response = chat_response.content
            else:
                response = str(chat_response)

            return {"success": True, "result": response}
        except Exception as e:
            logger.error(f"Chat execution error: {e}")
            return {"success": False, "error": str(e)}

    def _execute_blender(self, args: Dict[str, Any]) -> Dict[str, Any]:
        """Execute Blender operations."""
        # Implementation would go here
        return {"success": True, "result": "Blender operation completed"}

    def _execute_summarize(self, args: Dict[str, Any]) -> Dict[str, Any]:
        """Execute summarize operations.
        Returns either a non-streaming result or streaming iterator metadata.
        """
        collector = args.get("multipart_collector")
        if not collector:
            return {"success": False, "error": "Missing multipart_collector"}

        file_rec = collector.files.get("file")
        style_bytes = collector.fields.get("style") or b"brief"
        stream_val = collector.fields.get("stream")
        accept_sse = bool(args.get("accept_sse"))

        # Normalize flags
        try:
            style = (
                style_bytes.decode("utf-8", errors="ignore")
                if isinstance(style_bytes, (bytes, bytearray))
                else str(style_bytes)
            )
        except Exception:
            style = "brief"
        try:
            stream = str(
                (
                    stream_val.decode("utf-8")
                    if isinstance(stream_val, (bytes, bytearray))
                    else stream_val
                )
                or ""
            ).lower() in ["1", "true", "yes"]
        except Exception:
            stream = False
        # Honor Accept: text/event-stream if not explicitly set by field
        if not stream and accept_sse:
            stream = True

        if not file_rec:
            return {"success": False, "error": "No file uploaded"}

        # Save file to temp
        filename = file_rec.get("file_name")
        ext = os.path.splitext(filename)[1] if filename else ".pdf"
        tmpfile_path = None
        try:
            with tempfile.NamedTemporaryFile(
                delete=False, suffix=ext or ".pdf"
            ) as tmpfile:
                buf = file_rec.get("file_object")
                buf.seek(0)
                shutil.copyfileobj(buf, tmpfile)
                tmpfile_path = tmpfile.name

            # Initialize agent
            agent_config = self.agents.get("summarize")
            if not agent_config:
                return {"success": False, "error": "Summarize agent not available"}
            if "instance" not in agent_config:
                agent_class = agent_config["class"]
                init_params = agent_config.get("init_params", {})
                agent_config["instance"] = agent_class(**init_params)
            agent = agent_config["instance"]

            # Validate style early to provide clear error message
            try:
                agent._validate_styles(style)  # pylint: disable=protected-access
            except ValueError as e:
                return {"success": False, "error": str(e)}

            if stream:
                content = agent.get_summary_content_from_file(Path(tmpfile_path))
                if not content:
                    return {
                        "success": False,
                        "error": "No extractable text found in uploaded file",
                    }
                iterator = agent.summarize_stream(
                    content, input_type="pdf", style=style
                )
                # Return tmpfile_path for cleanup after streaming completes
                return {
                    "success": True,
                    "stream": True,
                    "style": style,
                    "tmpfile_path": tmpfile_path,
                    "iterator": iterator,
                }
            else:
                result = agent.summarize_file(tmpfile_path, styles=[style])
                return {
                    "success": True,
                    "stream": False,
                    "style": style,
                    "result": result,
                }
        finally:
            # Clean up temp file for non-streaming responses or on error
            # For streaming responses, cleanup happens in the HTTP handler after streaming completes
            if tmpfile_path and not stream and os.path.exists(tmpfile_path):
                try:
                    os.unlink(tmpfile_path)
                except Exception as e:
                    logger.warning(f"Failed to cleanup temp file {tmpfile_path}: {e}")


class MCPHTTPHandler(BaseHTTPRequestHandler):
    """HTTP handler for MCP protocol."""

    def __init__(self, *args, bridge: GAIAMCPBridge = None, **kwargs):
        self.bridge = bridge or GAIAMCPBridge()
        super().__init__(*args, **kwargs)

    def log_request_details(self, method, path, body=None):
        """Log incoming request details if verbose mode is enabled."""
        if VERBOSE:
            client_addr = self.client_address[0] if self.client_address else "unknown"
            logger.info(f"MCP Request: {method} {path} from {client_addr}")
            if body:
                logger.debug(f"Request body: {json.dumps(body, indent=2)}")

    def do_GET(self):
        """Handle GET requests."""
        self.log_request_details("GET", self.path)
        parsed = urlparse(self.path)

        if parsed.path == "/health":
            self.send_json(
                200,
                {
                    "status": "healthy",
                    "service": "GAIA MCP Bridge (HTTP)",
                    "agents": len(self.bridge.agents),
                    "tools": len(self.bridge.tools),
                },
            )
        elif parsed.path == "/tools" or parsed.path == "/v1/tools":
            self.send_json(200, {"tools": list(self.bridge.tools.values())})
        elif parsed.path == "/status":
            # Comprehensive status endpoint with all details
            agents_info = {}
            for name, agent in self.bridge.agents.items():
                agents_info[name] = {
                    "description": agent.get("description", ""),
                    "capabilities": agent.get("capabilities", []),
                    "type": "class" if "class" in agent else "module",
                }

            tools_info = {}
            for name, tool in self.bridge.tools.items():
                tools_info[name] = {
                    "description": tool.get("description", ""),
                    "inputSchema": tool.get("inputSchema", {}),
                }

            self.send_json(
                200,
                {
                    "status": "healthy",
                    "service": "GAIA MCP Bridge (HTTP)",
                    "version": "2.0.0",
                    "host": self.bridge.host,
                    "port": self.bridge.port,
                    "llm_backend": self.bridge.base_url,
                    "agents": agents_info,
                    "tools": tools_info,
                    "endpoints": {
                        "health": "GET /health - Health check",
                        "status": "GET /status - Detailed status (this endpoint)",
                        "tools": "GET /tools - List available tools",
                        "chat": "POST /chat - Interactive chat",
                        "jira": "POST /jira - Jira operations",
                        "llm": "POST /llm - Direct LLM queries",
                        "jsonrpc": "POST / - JSON-RPC endpoint",
                    },
                },
            )
        else:
            self.send_json(404, {"error": "Not found"})

    def do_POST(self):
        """Handle POST requests - main MCP endpoint."""
        content_length = int(self.headers.get("Content-Length", 0))

        parsed = urlparse(self.path)
        ctype = self.headers.get("content-type", "")

        if ctype.startswith("application/json") and content_length > 0:
            body = self.rfile.read(content_length)
            try:
                data = json.loads(body.decode("utf-8"))
                self.log_request_details("POST", self.path, data)
            except json.JSONDecodeError:
                self.log_request_details("POST", self.path)
                logger.error("Invalid JSON in request body")
                self.send_json(400, {"error": "Invalid JSON"})
                return
        elif ctype.startswith("multipart/form-data"):
            raw_data = self.rfile.read(content_length)

            # Extract boundary using python-multipart helper and ensure bytes
            _, opts = parse_options_header(ctype)
            boundary = opts.get(b"boundary")
            if not boundary:
                raise ValueError("Missing multipart boundary")

            # boundary is bytes, decode for parser if needed
            boundary = boundary.decode("latin-1").strip('"')
            boundary_bytes = (
                boundary
                if isinstance(boundary, (bytes, bytearray))
                else str(boundary).encode("utf-8")
            )

            collector = MultipartCollector()
            mp = MultipartParser(boundary_bytes, callbacks=collector.callbacks())
            mp.write(raw_data)
            mp.finalize()
            data = {}
            data["multipart_collector"] = collector
        else:
            data = {}
            self.log_request_details("POST", self.path)

        # Handle different endpoints
        if parsed.path in ["/", "/v1/messages", "/rpc"]:
            # JSON-RPC endpoint
            self.handle_jsonrpc(data)
        elif parsed.path == "/chat":
            # Direct chat endpoint for conversations
            result = self.bridge.execute_tool("gaia.chat", data)
            self.send_json(200 if result.get("success") else 500, result)
        elif parsed.path == "/jira":
            # Direct Jira endpoint for convenience
            result = self.bridge.execute_tool("gaia.jira", data)
            self.send_json(200 if result.get("success") else 500, result)
        elif parsed.path == "/llm":
            # Direct LLM endpoint (no conversation context)
            result = self.bridge.execute_tool("gaia.query", data)
            self.send_json(200 if result.get("success") else 500, result)
        elif parsed.path == "/summarize":
            # Direct Summarize endpoint accept multipart/form-data (file upload) for browser clients
            accept_header = self.headers.get("Accept", "")
            if isinstance(data, dict):
                data["accept_sse"] = "text/event-stream" in accept_header
            result = self.bridge.execute_tool("gaia.summarize", data)
            if result.get("success") and result.get("stream"):
                self.send_sse_headers()
                try:
                    self.stream_sse(result.get("iterator", []))
                finally:
                    tmp = result.get("tmpfile_path")
                    if tmp and os.path.exists(tmp):
                        os.unlink(tmp)
                return
            else:
                self.send_json(200 if result.get("success") else 500, result)
                return
        else:
            self.send_json(404, {"error": "Not found"})

    def handle_jsonrpc(self, data):
        """Handle JSON-RPC requests."""
        # Validate JSON-RPC
        if "jsonrpc" not in data or data["jsonrpc"] != "2.0":
            self.send_json(
                400,
                {
                    "jsonrpc": "2.0",
                    "error": {"code": -32600, "message": "Invalid Request"},
                    "id": data.get("id"),
                },
            )
            return

        method = data.get("method")
        params = data.get("params", {})
        request_id = data.get("id")

        # Route methods
        if method == "initialize":
            result = {
                "protocolVersion": "1.0.0",
                "serverInfo": {"name": "GAIA MCP Bridge", "version": "2.0.0"},
                "capabilities": {"tools": True, "resources": True, "prompts": True},
            }
        elif method == "tools/list":
            result = {"tools": list(self.bridge.tools.values())}
        elif method == "tools/call":
            tool_name = params.get("name")
            arguments = params.get("arguments", {})
            tool_result = self.bridge.execute_tool(tool_name, arguments)
            result = {"content": [{"type": "text", "text": json.dumps(tool_result)}]}
        else:
            self.send_json(
                400,
                {
                    "jsonrpc": "2.0",
                    "error": {"code": -32601, "message": f"Method not found: {method}"},
                    "id": request_id,
                },
            )
            return

        # Send response
        self.send_json(200, {"jsonrpc": "2.0", "result": result, "id": request_id})

    def do_OPTIONS(self):
        """Handle OPTIONS for CORS."""
        self.log_request_details("OPTIONS", self.path)
        self.send_response(200)
        self.send_header("Access-Control-Allow-Origin", "*")
        self.send_header("Access-Control-Allow-Methods", "GET, POST, OPTIONS")
        self.send_header("Access-Control-Allow-Headers", "Content-Type")
        self.end_headers()

    def send_sse_headers(self):
        """Send standard headers for Server-Sent Events."""
        self.send_response(200)
        self.send_header("Content-Type", "text/event-stream")
        self.send_header("Cache-Control", "no-cache")
        self.send_header("Access-Control-Allow-Origin", "*")
        self.send_header("Connection", "keep-alive")
        self.send_header("X-Accel-Buffering", "no")
        self.end_headers()

    def stream_sse(self, iterator):
        """Stream SSE data from an iterator of chunk dicts."""
        for chunk in iterator:
            if chunk.get("is_complete"):
                data_out = json.dumps(
                    {"event": "complete", "performance": chunk.get("performance", {})}
                )
            else:
                data_out = json.dumps({"text": chunk.get("text", "")})
            self.wfile.write(f"data: {data_out}\n\n".encode("utf-8"))
            self.wfile.flush()

    def send_json(self, status, data):
        """Send JSON response."""
        if VERBOSE:
            logger.info(f"MCP Response: Status {status}")
            logger.debug(f"Response body: {json.dumps(data, indent=2)}")

        self.send_response(status)
        self.send_header("Content-Type", "application/json")
        self.send_header("Access-Control-Allow-Origin", "*")
        self.end_headers()
        self.wfile.write(json.dumps(data).encode("utf-8"))

    def log_message(self, format, *args):
        """Override to control standard HTTP logging."""
        # In verbose mode, skip the built-in HTTP logging since we have custom logging
        if VERBOSE:
            # We already log detailed info in log_request_details and send_json
            pass
        elif "/health" not in args[0]:
            # In non-verbose mode, skip health checks but log everything else
            super().log_message(format, *args)


def start_server(host="localhost", port=8765, base_url=None, verbose=False):
    """Start the HTTP MCP server."""
    import io

    # Fix Windows Unicode
    if sys.platform == "win32":
        sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding="utf-8")

    # Fix Linux IPv6 issue: When host is "localhost", Python's socket might bind
    # to ::1 (IPv6) which curl can't connect to by default. Use 0.0.0.0 on Linux
    # to bind to all IPv4 interfaces. Keep localhost on Windows where it works.
    bind_host = host
    if host == "localhost" and sys.platform != "win32":
        bind_host = "0.0.0.0"

    logger.info(f"Creating MCP bridge for {host}:{port}")

    # Create bridge with verbose flag
    bridge = GAIAMCPBridge(host, port, base_url, verbose=verbose)

    # Create handler with bridge
    def handler(*args, **kwargs):
        return MCPHTTPHandler(*args, bridge=bridge, **kwargs)

    # Start server - use bind_host for actual socket binding
    logger.info(f"Creating HTTP server on {bind_host}:{port}")
    try:
        server = HTTPServer((bind_host, port), handler)
        logger.info(
            f"HTTP server created successfully, listening on {bind_host}:{port}"
        )
    except Exception as e:
        logger.error(f"Failed to create HTTP server: {e}")
        raise

    print("=" * 60, flush=True)
    print("🚀 GAIA MCP Bridge - HTTP Native")
    print("=" * 60)
    print(f"Server: http://{host}:{port}")
    print(f"LLM Backend: {bridge.base_url}")
    print(f"Agents: {list(bridge.agents.keys())}")
    print(f"Tools: {list(bridge.tools.keys())}")
    if verbose:
        print(f"\n🔍 Verbose Mode: ENABLED")
        print(f"   All requests will be logged to console and gaia.log")
        logger.info("MCP Bridge started in VERBOSE mode - all requests will be logged")
    print("\n📍 Endpoints:")
    print(f"  GET  http://{host}:{port}/health     - Health check")
    print(
        f"  GET  http://{host}:{port}/status      - Detailed status with agents & tools"
    )
    print(f"  GET  http://{host}:{port}/tools      - List tools")
    print(f"  POST http://{host}:{port}/           - JSON-RPC")
    print(f"  POST http://{host}:{port}/chat       - Chat (with context)")
    print(f"  POST http://{host}:{port}/jira       - Direct Jira")
    print(f"  POST http://{host}:{port}/llm        - Direct LLM (no context)")
    print("\n🔧 Usage Examples:")
    print(
        '  Chat: curl -X POST http://localhost:8765/chat -d \'{"query":"Hello GAIA!"}\''
    )
    print(
        '  Jira: curl -X POST http://localhost:8765/jira -d \'{"query":"show my issues"}\''
    )
    print('  n8n: HTTP Request → POST /chat → {"query": "..."}')
    print("  MCP: JSON-RPC to / with method: tools/call")
    print("=" * 60)
    print("\nPress Ctrl+C to stop\n", flush=True)

    logger.info(f"Starting serve_forever() on {bind_host}:{port}")
    try:
        server.serve_forever()
    except KeyboardInterrupt:
        print("\n✅ Server stopped")


if __name__ == "__main__":
    import argparse

    parser = argparse.ArgumentParser(description="GAIA MCP Bridge - HTTP Native")
    parser.add_argument("--host", default="localhost", help="Host to bind to")
    parser.add_argument("--port", type=int, default=8765, help="Port to listen on")
    parser.add_argument(
        "--base-url", default="http://localhost:8000/api/v1", help="LLM server URL"
    )
    parser.add_argument(
        "--verbose", action="store_true", help="Enable verbose logging for all requests"
    )

    args = parser.parse_args()
    start_server(args.host, args.port, args.base_url, args.verbose)
