"""PoolClaw Remote MCP Server.

Exposes the same tools as the local stdio MCP server but over HTTP/SSE,
so users can connect from Claude Settings without installing anything locally.

Deploy on Render:
    Start command: poolclaw-mcp-remote
    Environment variables:
        POOLCLAW_SERVER   PoolClaw API URL (default: https://poolclaw-python.onrender.com)
        POOLCLAW_FRONTEND Frontend URL (default: https://poolclaw-frontend.onrender.com)
        PORT              Port to listen on (default: 8080, set by Render automatically)

User setup (no terminal needed):
    Claude Settings → Connectors → Add custom connector
    URL:   https://mcp.poolclaw.ai/mcp
    Token: <their PoolClaw agent token>
"""
from __future__ import annotations

import logging
import os

import httpx
import uvicorn
from starlette.applications import Starlette
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.requests import Request
from starlette.responses import JSONResponse
from starlette.routing import Route

from poolclaw_mcp.server import SERVER_URL, _remote_token, mcp

log = logging.getLogger("poolclaw_mcp.remote")


# ── Auth middleware ────────────────────────────────────────────────────────────

class AgentTokenMiddleware(BaseHTTPMiddleware):
    """Validate the Bearer token on every request and set it in the contextvar.

    Claude sends:  Authorization: Bearer <poolclaw_agent_token>
    We validate against the PoolClaw API and store the token in _remote_token
    so all tool handlers can use it without touching global state.
    """

    _NO_AUTH_PATHS = {"/health", "/"}

    async def dispatch(self, request: Request, call_next):
        if request.url.path in self._NO_AUTH_PATHS:
            return await call_next(request)

        auth = request.headers.get("Authorization", "")
        if not auth.startswith("Bearer "):
            return JSONResponse(
                {"error": "Missing or invalid Authorization header. Use: Bearer <your_poolclaw_token>"},
                status_code=401,
            )

        token = auth[7:].strip()
        if not token:
            return JSONResponse({"error": "Empty token"}, status_code=401)

        # Validate token against PoolClaw API
        try:
            async with httpx.AsyncClient(timeout=5) as client:
                resp = await client.get(
                    f"{SERVER_URL}/wallet/agent",
                    headers={"X-Agent-Token": token},
                    follow_redirects=False,
                )
            if resp.status_code == 401 or resp.status_code == 403:
                return JSONResponse({"error": "Invalid PoolClaw token"}, status_code=401)
        except httpx.RequestError as exc:
            log.warning("Token validation failed (network): %s", exc)
            return JSONResponse({"error": "Could not reach PoolClaw API"}, status_code=503)

        # Inject token into contextvar for this request's scope
        tok = _remote_token.set(token)
        try:
            response = await call_next(request)
        finally:
            _remote_token.reset(tok)

        return response


# ── Health endpoint ────────────────────────────────────────────────────────────

async def health(request: Request) -> JSONResponse:
    return JSONResponse({"status": "ok", "service": "poolclaw-mcp-remote"})


# ── Build the ASGI app ─────────────────────────────────────────────────────────

def build_app() -> Starlette:
    # Get the SSE ASGI app from FastMCP
    sse_asgi = mcp.sse_app()

    app = Starlette(
        routes=[Route("/health", health)],
    )

    # Mount MCP SSE at /mcp — Claude connects to https://your-domain.com/mcp
    app.mount("/mcp", sse_asgi)

    # Auth middleware runs on all routes (health is excluded inside the middleware)
    app.add_middleware(AgentTokenMiddleware)

    return app


app = build_app()


# ── Entry point ────────────────────────────────────────────────────────────────

def main() -> None:
    port = int(os.environ.get("PORT", "8080"))
    log.info("Starting PoolClaw Remote MCP on port %d", port)
    uvicorn.run(
        "poolclaw_mcp.remote:app",
        host="0.0.0.0",
        port=port,
        log_level="warning",
    )


if __name__ == "__main__":
    main()
