"""
Entrypoint for the remote MCP server.

Starts the FastMCP server with Streamable HTTP transport,
with OAuth token verification middleware and well-known endpoints.
"""

import logging
import os
import sys

from dotenv import load_dotenv

load_dotenv()

# Configure logging before anything else
log = logging.getLogger(__name__)

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s [%(name)s] %(levelname)s: %(message)s",
    stream=sys.stderr,
)

# Initialize Sentry before Django setup
if os.environ.get("SENTRY_DSN"):
    import sentry_sdk
    from sentry_sdk.integrations.mcp import MCPIntegration

    sentry_sdk.init(
        dsn=os.environ["SENTRY_DSN"],
        traces_sample_rate=1.0,
        send_default_pii=True,
        environment="production",
        integrations=[
            MCPIntegration(),
        ],
    )


from starlette.middleware.base import BaseHTTPMiddleware
from starlette.middleware.cors import CORSMiddleware
from starlette.requests import Request
from starlette.responses import FileResponse, JSONResponse, Response
from starlette.routing import Route

from .auth import OAuthTokenMiddleware
from .constants import (
    PATH_FAVICON,
    PATH_HEALTH,
    PATH_MCP_SERVER_CARD,
    PATH_OAUTH_AUTHORIZATION_SERVER,
    PATH_OAUTH_OPENID_CONFIGURATION,
    PATH_OAUTH_PROTECTED_RESOURCE,
    PATH_OAUTH_REGISTER,
    PATH_ROBOTS,
    SLUG_PREFIX,
)
from .server import MCP_SERVER_VERSION, mcp, mcp_server_url
from .wellknown import authorization_server_metadata, openid_configuration, protected_resource_metadata, register_client

FAVICON_PATH = os.path.join(os.path.dirname(__file__), "favicon.ico")


async def health(request: Request) -> JSONResponse:
    return JSONResponse({"status": "ok"})


async def favicon(request: Request) -> FileResponse:
    return FileResponse(FAVICON_PATH, media_type="image/x-icon")


async def robots_txt(request: Request) -> Response:
    return Response(
        content="User-agent: *\nAllow: /.well-known/\nDisallow: /\n",
        media_type="text/plain",
    )


async def server_card(request: Request) -> JSONResponse:
    """/.well-known/mcp/server-card.json — static discovery metadata."""
    return JSONResponse(
        {
            "protocolVersion": "2025-03-26",
            "serverInfo": {
                "name": "obris",
                "title": "Obris",
                "version": MCP_SERVER_VERSION,
                "websiteUrl": "https://obris.ai",
                "icons": [{"src": "https://raw.githubusercontent.com/obris-dev/obris-mcp/main/icon.svg"}],
            },
            "instructions": "Obris gives AI assistants access to your personal knowledge base. Use the tools to list topics and retrieve saved knowledge.",
            "capabilities": {
                "prompts": {"listChanged": False},
                "resources": {"subscribe": False, "listChanged": False},
                "tools": {"listChanged": False},
            },
            "transport": {
                "type": "streamable-http",
                "endpoint": f"{mcp_server_url}/",
            },
            "authentication": {
                "required": True,
                "schemes": [{"type": "oauth2"}],
            },
            "tools": ["dynamic"],
            "prompts": ["dynamic"],
            "resources": ["dynamic"],
        }
    )


class ExpertPathRewriteMiddleware(BaseHTTPMiddleware):
    """Rewrite /u/{slug} paths before auth and routing.

    Strips the /u/{slug} prefix and stores the slug in request.scope
    so OAuthTokenMiddleware can resolve it to an expert ID downstream.
    """

    async def dispatch(self, request: Request, call_next):
        path = request.url.path
        if path.startswith(SLUG_PREFIX):
            # Strip /u/{slug} prefix, preserving any trailing path.
            # e.g. /u/my-expert/.well-known/... → /.well-known/...
            # e.g. /u/my-expert → /
            rest = path[len(SLUG_PREFIX) :]
            slug = rest.split("/")[0]
            slash_idx = rest.find("/")
            rewritten = rest[slash_idx:] if slash_idx != -1 else "/"
            request.scope["path"] = rewritten
            request.scope["expert_slug"] = slug
        return await call_next(request)


def create_app():
    """ASGI app factory — used by uvicorn for both production and reload mode."""
    app = mcp.streamable_http_app()

    # Add routes before MCP catch-all
    app.routes.insert(0, Route(PATH_ROBOTS, robots_txt, methods=["GET"]))
    app.routes.insert(0, Route(PATH_FAVICON, favicon, methods=["GET"]))
    app.routes.insert(0, Route(PATH_HEALTH, health, methods=["GET"]))
    app.routes.insert(0, Route(PATH_OAUTH_PROTECTED_RESOURCE, protected_resource_metadata, methods=["GET"]))
    app.routes.insert(0, Route(PATH_OAUTH_AUTHORIZATION_SERVER, authorization_server_metadata, methods=["GET"]))
    app.routes.insert(0, Route(PATH_OAUTH_OPENID_CONFIGURATION, openid_configuration, methods=["GET"]))
    app.routes.insert(0, Route(PATH_MCP_SERVER_CARD, server_card, methods=["GET"]))
    app.routes.insert(0, Route(PATH_OAUTH_REGISTER, register_client, methods=["POST"]))

    # Add OAuth middleware (outermost — runs first)
    app.add_middleware(OAuthTokenMiddleware)

    # Rewrite /u/{slug} paths to / after auth has resolved the expert
    app.add_middleware(ExpertPathRewriteMiddleware)

    # CORS — allow browser-based MCP clients (e.g. MCP Inspector)
    app.add_middleware(
        CORSMiddleware,
        allow_origins=["*"],
        allow_methods=["*"],
        allow_headers=["*"],
        expose_headers=["*"],
    )

    return app


def main():
    import uvicorn

    host = os.environ.get("MCP_HOST", "0.0.0.0")
    port = int(os.environ.get("MCP_PORT", "8001"))
    reload = os.environ.get("MCP_RELOAD", "").lower() in ("1", "true")

    log.info("MCP server starting on %s:%s (reload=%s)", host, port, reload)
    uvicorn.run("obris_mcp.remote.run:create_app", factory=True, host=host, port=port, reload=reload)


if __name__ == "__main__":
    main()
