#!/usr/bin/env python3
"""
Genesis Voice Bridge - HTTP Transport Layer
============================================
Exposes Genesis MCP tools over HTTP for Telnyx AI Assistant integration.

Architecture:
- FastAPI HTTP server listening on configurable port
- Bridges Telnyx webhook calls → MCP tool execution
- Supports real-time tool invocation during voice calls
- Returns JSON responses compatible with Telnyx AI Assistant

Endpoints:
- POST /webhook/telnyx - Main Telnyx webhook handler
- POST /tools/{tool_name} - Direct MCP tool invocation
- GET /health - Health check
- GET /tools - List available MCP tools

Usage:
    python http_transport.py --port 8765 --host 0.0.0.0
"""

import os
import sys
import json
import logging
import asyncio
from typing import Optional, Dict, Any, List
from datetime import datetime
from pathlib import Path

# Add genesis-core MCP server to path
sys.path.insert(0, str(Path(__file__).parent.parent / "genesis-core"))

try:
    from fastapi import FastAPI, HTTPException, Request, BackgroundTasks
    from fastapi.responses import JSONResponse
    from pydantic import BaseModel, Field
    import uvicorn
except ImportError:
    print("Installing required packages...")
    import subprocess
    subprocess.run([sys.executable, "-m", "pip", "install", "fastapi", "uvicorn[standard]", "pydantic"], check=True)
    from fastapi import FastAPI, HTTPException, Request, BackgroundTasks
    from fastapi.responses import JSONResponse
    from pydantic import BaseModel, Field
    import uvicorn

# Import Genesis MCP tools
try:
    from server import (
        search_memory, store_memory, create_relation,
        trigger_workflow, execute_skill, get_status,
        load_memory_graph, save_memory_graph, get_available_skills
    )
    MCP_TOOLS_AVAILABLE = True
except ImportError as e:
    logging.warning(f"Genesis MCP tools not available: {e}")
    MCP_TOOLS_AVAILABLE = False

# =============================================================================
# Configuration
# =============================================================================

GENESIS_ROOT = Path("/mnt/e/genesis-system")
LOG_DIR = GENESIS_ROOT / "logs" / "voice-bridge"
LOG_DIR.mkdir(parents=True, exist_ok=True)

# Setup logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
    handlers=[
        logging.FileHandler(LOG_DIR / f"http_transport_{datetime.now().strftime('%Y%m%d')}.log"),
        logging.StreamHandler()
    ]
)
logger = logging.getLogger("genesis-voice-bridge")

# =============================================================================
# Pydantic Models
# =============================================================================

class TelnyxWebhookEvent(BaseModel):
    """Telnyx webhook event structure."""
    event_type: str
    id: str
    occurred_at: str
    payload: Dict[str, Any]

class MCPToolRequest(BaseModel):
    """MCP tool invocation request."""
    tool_name: str
    parameters: Dict[str, Any] = Field(default_factory=dict)
    context: Optional[Dict[str, Any]] = Field(default_factory=dict)

class MCPToolResponse(BaseModel):
    """MCP tool response."""
    success: bool
    tool_name: str
    result: Any
    error: Optional[str] = None
    timestamp: str = Field(default_factory=lambda: datetime.now().isoformat())

class HealthResponse(BaseModel):
    """Health check response."""
    status: str
    timestamp: str
    mcp_available: bool
    version: str = "1.0.0"

# =============================================================================
# FastAPI Application
# =============================================================================

app = FastAPI(
    title="Genesis Voice Bridge",
    description="HTTP transport layer for Genesis MCP tools + Telnyx integration",
    version="1.0.0"
)

# =============================================================================
# MCP Tool Registry
# =============================================================================

MCP_TOOL_REGISTRY = {
    "search_memory": {
        "function": search_memory if MCP_TOOLS_AVAILABLE else None,
        "description": "Search Genesis knowledge graph",
        "parameters": ["query", "entity_type", "limit"]
    },
    "store_memory": {
        "function": store_memory if MCP_TOOLS_AVAILABLE else None,
        "description": "Store new entity in knowledge graph",
        "parameters": ["name", "entity_type", "observations"]
    },
    "create_relation": {
        "function": create_relation if MCP_TOOLS_AVAILABLE else None,
        "description": "Create relationship between entities",
        "parameters": ["from_entity", "relation_type", "to_entity"]
    },
    "trigger_workflow": {
        "function": trigger_workflow if MCP_TOOLS_AVAILABLE else None,
        "description": "Trigger n8n workflow",
        "parameters": ["workflow_name", "input_data"]
    },
    "execute_skill": {
        "function": execute_skill if MCP_TOOLS_AVAILABLE else None,
        "description": "Execute Genesis skill",
        "parameters": ["skill_name", "parameters"]
    },
    "get_status": {
        "function": get_status if MCP_TOOLS_AVAILABLE else None,
        "description": "Get Genesis system status",
        "parameters": []
    }
}

# =============================================================================
# Helper Functions
# =============================================================================

def execute_mcp_tool(tool_name: str, parameters: Dict[str, Any]) -> Dict[str, Any]:
    """Execute an MCP tool and return structured result."""
    if not MCP_TOOLS_AVAILABLE:
        return {
            "success": False,
            "error": "MCP tools not available - genesis-core server not found"
        }

    tool = MCP_TOOL_REGISTRY.get(tool_name)
    if not tool:
        return {
            "success": False,
            "error": f"Tool '{tool_name}' not found. Available: {list(MCP_TOOL_REGISTRY.keys())}"
        }

    try:
        # Call the MCP tool function
        result = tool["function"](**parameters)

        # Parse JSON result (MCP tools return JSON strings)
        if isinstance(result, str):
            try:
                result = json.loads(result)
            except json.JSONDecodeError:
                pass

        return {
            "success": True,
            "result": result
        }
    except Exception as e:
        logger.error(f"Error executing MCP tool {tool_name}: {e}", exc_info=True)
        return {
            "success": False,
            "error": str(e)
        }

async def log_webhook_event(event: Dict[str, Any], response: Dict[str, Any]):
    """Log webhook events for debugging."""
    log_file = LOG_DIR / f"webhook_events_{datetime.now().strftime('%Y%m%d')}.jsonl"
    log_entry = {
        "timestamp": datetime.now().isoformat(),
        "event": event,
        "response": response
    }
    with open(log_file, "a") as f:
        f.write(json.dumps(log_entry) + "\n")

# =============================================================================
# Routes
# =============================================================================

@app.get("/health", response_model=HealthResponse)
async def health_check():
    """Health check endpoint."""
    return HealthResponse(
        status="operational",
        timestamp=datetime.now().isoformat(),
        mcp_available=MCP_TOOLS_AVAILABLE
    )

@app.get("/tools")
async def list_tools():
    """List all available MCP tools."""
    tools = {}
    for name, meta in MCP_TOOL_REGISTRY.items():
        tools[name] = {
            "description": meta["description"],
            "parameters": meta["parameters"],
            "available": meta["function"] is not None
        }
    return {
        "total": len(tools),
        "mcp_available": MCP_TOOLS_AVAILABLE,
        "tools": tools
    }

@app.post("/tools/{tool_name}")
async def invoke_tool(tool_name: str, request: MCPToolRequest):
    """
    Direct MCP tool invocation endpoint.

    Example:
        POST /tools/search_memory
        {
            "tool_name": "search_memory",
            "parameters": {"query": "AIVA", "limit": 5}
        }
    """
    logger.info(f"Tool invocation: {tool_name} with params: {request.parameters}")

    result = execute_mcp_tool(tool_name, request.parameters)

    return MCPToolResponse(
        success=result["success"],
        tool_name=tool_name,
        result=result.get("result"),
        error=result.get("error")
    )

@app.post("/webhook/telnyx")
async def telnyx_webhook(request: Request, background_tasks: BackgroundTasks):
    """
    Main Telnyx webhook handler.

    Processes Telnyx AI Assistant events and executes Genesis MCP tools.

    Supported event types:
    - call.initiated: Log call start
    - call.answered: Activate voice assistant
    - assistant.tool_call: Execute MCP tool during call
    - call.hangup: Log call completion
    """
    try:
        payload = await request.json()
        event_type = payload.get("event_type", "unknown")

        logger.info(f"Telnyx webhook: {event_type}")
        logger.debug(f"Payload: {json.dumps(payload, indent=2)}")

        response_data = {
            "status": "received",
            "event_type": event_type,
            "timestamp": datetime.now().isoformat()
        }

        # Handle different event types
        if event_type == "call.initiated":
            response_data["message"] = "Call logged"
            response_data["actions"] = []

        elif event_type == "call.answered":
            response_data["message"] = "Voice assistant activated"
            response_data["actions"] = ["start_recording", "enable_assistant"]

        elif event_type == "assistant.tool_call":
            # Extract tool call from payload
            tool_call = payload.get("payload", {}).get("tool_call", {})
            tool_name = tool_call.get("name")
            parameters = tool_call.get("parameters", {})

            if tool_name:
                # Execute MCP tool
                result = execute_mcp_tool(tool_name, parameters)
                response_data["tool_result"] = result
                response_data["actions"] = ["respond_to_caller"]
            else:
                response_data["error"] = "No tool_name in assistant.tool_call event"

        elif event_type == "call.hangup":
            response_data["message"] = "Call completed"
            response_data["actions"] = ["finalize_recording", "store_transcript"]

        else:
            response_data["message"] = f"Unhandled event type: {event_type}"

        # Log event asynchronously
        background_tasks.add_task(log_webhook_event, payload, response_data)

        return JSONResponse(content=response_data)

    except Exception as e:
        logger.error(f"Webhook processing error: {e}", exc_info=True)
        raise HTTPException(status_code=500, detail=str(e))

@app.post("/assistant/tools")
async def assistant_tool_definitions():
    """
    Return Genesis MCP tools in Telnyx AI Assistant tool schema format.

    This endpoint provides tool definitions that can be configured in the
    Telnyx AI Assistant to enable real-time Genesis tool calls during voice calls.
    """
    if not MCP_TOOLS_AVAILABLE:
        return {
            "error": "MCP tools not available",
            "tools": []
        }

    # Convert MCP tools to Telnyx tool schema
    tools = []
    for name, meta in MCP_TOOL_REGISTRY.items():
        if meta["function"]:
            tool_def = {
                "name": name,
                "description": meta["description"],
                "parameters": {
                    "type": "object",
                    "properties": {},
                    "required": []
                }
            }

            # Add parameter schemas (simplified - would need full type info)
            for param in meta["parameters"]:
                tool_def["parameters"]["properties"][param] = {
                    "type": "string",  # Simplified - real impl would need proper types
                    "description": f"Parameter: {param}"
                }

            tools.append(tool_def)

    return {
        "tools": tools,
        "webhook_url": "https://genesis.agileadapt.com/webhook/telnyx",  # TODO: Replace with actual domain
        "version": "1.0.0"
    }

# =============================================================================
# Main Entry Point
# =============================================================================

def main():
    """Run the HTTP transport server."""
    import argparse

    parser = argparse.ArgumentParser(description="Genesis Voice Bridge HTTP Transport")
    parser.add_argument("--host", default="0.0.0.0", help="Host to bind to")
    parser.add_argument("--port", type=int, default=8765, help="Port to listen on")
    parser.add_argument("--reload", action="store_true", help="Enable auto-reload (dev mode)")

    args = parser.parse_args()

    logger.info(f"Starting Genesis Voice Bridge on {args.host}:{args.port}")
    logger.info(f"MCP Tools Available: {MCP_TOOLS_AVAILABLE}")

    if not MCP_TOOLS_AVAILABLE:
        logger.warning("Genesis MCP tools not loaded - server will run in limited mode")

    uvicorn.run(
        "http_transport:app",
        host=args.host,
        port=args.port,
        reload=args.reload,
        log_level="info"
    )

if __name__ == "__main__":
    main()
