#!/usr/bin/env python3
"""
Genesis Voice Webhook Server — Queue Edition
Runs locally on Windows/WSL2 port 8765.
Receives commands from Telnyx Qwen3 AI Assistant via cloudflared tunnel.
Writes commands to /tmp/genesis_voice_queue.jsonl for relay injection into Claude Code terminal.

Usage:
    uv run tools/genesis_voice_webhook.py
    # or: pip install fastapi uvicorn && python tools/genesis_voice_webhook.py
"""
# /// script
# requires-python = ">=3.10"
# dependencies = ["fastapi", "uvicorn[standard]"]
# ///

import json
import logging
import os
import sys
import time
import uuid
from datetime import datetime, timezone
from pathlib import Path

import uvicorn
from fastapi import FastAPI, HTTPException, Request
from fastapi.middleware.cors import CORSMiddleware

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(levelname)s] %(message)s",
    handlers=[logging.StreamHandler(sys.stdout)],
)
log = logging.getLogger(__name__)

app = FastAPI(title="Genesis Voice Webhook", version="2.0.0")

app.add_middleware(
    CORSMiddleware,
    allow_origins=["*"],
    allow_methods=["*"],
    allow_headers=["*"],
)

# Queue file — relay watches this file for new commands
QUEUE_FILE = Path("/tmp/genesis_voice_queue.jsonl")
RESULTS_FILE = Path("/tmp/genesis_voice_results.jsonl")


def _write_queue(command: str, caller_id: str = "") -> str:
    """Append a command to the queue file. Returns the command ID."""
    cmd_id = str(uuid.uuid4())[:8]
    record = {
        "id": cmd_id,
        "ts": datetime.now(timezone.utc).isoformat(),
        "command": command,
        "caller_id": caller_id,
        "status": "queued",
    }
    QUEUE_FILE.parent.mkdir(parents=True, exist_ok=True)
    with QUEUE_FILE.open("a") as f:
        f.write(json.dumps(record) + "\n")
    log.info(f"[QUEUE] {cmd_id}: {command[:80]}")
    return cmd_id


def _wait_for_result(cmd_id: str, timeout: float = 60.0) -> str:
    """Poll results file for a response to cmd_id. Returns result text."""
    deadline = time.time() + timeout
    while time.time() < deadline:
        if RESULTS_FILE.exists():
            with RESULTS_FILE.open() as f:
                for line in f:
                    try:
                        rec = json.loads(line.strip())
                        if rec.get("id") == cmd_id and rec.get("status") == "done":
                            return rec.get("result", "(no output)")
                    except json.JSONDecodeError:
                        pass
        time.sleep(0.5)
    return "(command queued — check your terminal for Claude's response)"


@app.get("/health")
async def health():
    return {
        "status": "ok",
        "server": "Genesis Voice Webhook",
        "version": "2.0.0",
        "mode": "tmux-relay",
        "queue": str(QUEUE_FILE),
    }


@app.post("/command")
async def queue_genesis_command(request: Request):
    """
    Receive a voice command from Telnyx Qwen3 assistant.
    Writes to queue file for relay injection into Claude Code terminal.

    Request body: {"command": "check the handoff file", "caller_id": "optional"}
    Response: {"result": "...", "success": true}
    """
    try:
        body = await request.json()
    except Exception:
        raise HTTPException(status_code=400, detail="Invalid JSON body")

    command = body.get("command", "").strip()
    if not command:
        raise HTTPException(status_code=400, detail="Missing 'command' field")

    caller_id = body.get("caller_id", "")
    cmd_id = _write_queue(command, caller_id)

    # Wait briefly for relay to process and Claude to respond
    # Voice TTS will speak whatever we return
    result = _wait_for_result(cmd_id, timeout=45.0)
    return {"result": result, "success": True, "command_id": cmd_id}


@app.post("/bash")
async def queue_bash_command(request: Request):
    """
    Queue a raw bash command (for quick status checks).
    Relayed via tmux send-keys wrapped in a claude -p call.
    """
    try:
        body = await request.json()
    except Exception:
        raise HTTPException(status_code=400, detail="Invalid JSON body")

    command = body.get("command", "").strip()
    if not command:
        raise HTTPException(status_code=400, detail="Missing 'command' field")

    # Safety: block destructive commands
    blocked = ["rm -rf", "del /f", "format ", "drop table", "truncate "]
    if any(b in command.lower() for b in blocked):
        return {"result": "Blocked: destructive command not allowed via voice.", "success": False}

    # Wrap bash in a natural language form for Claude
    full_command = f"run this bash command and show me the output: {command}"
    cmd_id = _write_queue(full_command)
    result = _wait_for_result(cmd_id, timeout=30.0)
    return {"result": result, "success": True}


if __name__ == "__main__":
    port = int(os.environ.get("GENESIS_VOICE_PORT", "8765"))
    log.info(f"Starting Genesis Voice Webhook v2.0 on port {port}")
    log.info(f"Queue file: {QUEUE_FILE}")
    log.info("Mode: tmux-relay (direct terminal injection)")
    uvicorn.run(app, host="0.0.0.0", port=port, log_level="info")
