"""CLI entry point for the Maeris MCP server."""

import asyncio
import contextlib
import logging
import os
from collections.abc import AsyncIterator
from pathlib import Path

import click
import structlog

from maeris_mcp.server import ServerConfig, create_server
from maeris_mcp.token_logger import write_session_summary


def _load_env_file() -> None:
    """Load server-level config from ~/.maeris/.env only.

    Intentionally does NOT load a project-local `.env` from the current
    working directory. The MCP server typically runs inside arbitrary repos
    (including untrusted ones), and project `.env` files often contain
    unrelated variables that could override Maeris settings.
    """
    try:
        from dotenv import load_dotenv  # type: ignore[import-not-found]

        cli_env = Path.home() / ".maeris" / ".env"
        if cli_env.exists():
            load_dotenv(cli_env, override=False)
    except ImportError:
        pass


_load_env_file()


def setup_logging(mode: str) -> tuple[int, str]:
    """Configure logging based on mode."""
    level_name = os.getenv("MAERIS_LOG_LEVEL", "DEBUG").upper()
    level = getattr(logging, level_name, logging.DEBUG)
    if mode == "http":
        # HTTP mode: log to console
        logging.basicConfig(level=level)
        structlog.configure(
            processors=[
                structlog.processors.TimeStamper(fmt="iso"),
                structlog.processors.add_log_level,
                structlog.dev.ConsoleRenderer(),
            ],
            wrapper_class=structlog.make_filtering_bound_logger(level),
        )
    else:
        # Stdio mode: log to file only (stderr is used for MCP protocol)
        import tempfile
        log_file = os.getenv("MAERIS_LOG_FILE") or os.path.join(tempfile.gettempdir(), "maeris.log")
        os.makedirs(os.path.dirname(log_file), exist_ok=True)
        file_handler = logging.FileHandler(log_file)
        file_handler.setLevel(level)

        logging.basicConfig(
            level=level,
            format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
            handlers=[file_handler],
        )

        structlog.configure(
            processors=[
                structlog.processors.TimeStamper(fmt="iso"),
                structlog.processors.add_log_level,
                structlog.processors.JSONRenderer(),
            ],
            logger_factory=structlog.PrintLoggerFactory(file=open(log_file, "a")),
            wrapper_class=structlog.make_filtering_bound_logger(level),
        )
    return level, level_name


@click.command()
@click.option(
    "--mode",
    default="stdio",
    type=click.Choice(["stdio", "http"]),
    help="Transport mode",
)
@click.option(
    "--port",
    default=None,
    help="HTTP port (only for http mode, defaults to PORT env var or 8080)",
)
def main(mode: str, port: str | None) -> None:
    """Maeris MCP Server - API extraction and documentation."""
    port = port or os.getenv("PORT", "8080")

    _, log_level_name = setup_logging(mode)
    logger = structlog.get_logger()

    config = ServerConfig()
    server = create_server(config)

    if mode == "http":
        logger.info("starting Maeris MCP server", mode="http", port=port, log_level=log_level_name)
        # HTTP mode with Streamable HTTP transport
        from mcp.server.streamable_http_manager import StreamableHTTPSessionManager
        from starlette.applications import Starlette
        from starlette.middleware import Middleware
        from starlette.middleware.cors import CORSMiddleware
        from starlette.requests import Request
        from starlette.responses import JSONResponse
        from starlette.routing import Mount, Route
        from starlette.types import Receive, Scope, Send
        import uvicorn

        session_manager = StreamableHTTPSessionManager(app=server)

        async def handle_mcp(scope: Scope, receive: Receive, send: Send) -> None:
            await session_manager.handle_request(scope, receive, send)

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

        @contextlib.asynccontextmanager
        async def lifespan(app: Starlette) -> AsyncIterator[None]:
            async with session_manager.run():
                logger.info("streamable HTTP session manager started")
                yield
            write_session_summary()

        starlette_app = Starlette(
            routes=[
                Route("/health", endpoint=health),
                Mount("/mcp", app=handle_mcp),
            ],
            middleware=[
                Middleware(
                    CORSMiddleware,
                    allow_origins=["*"],
                    allow_methods=["GET", "POST", "DELETE", "OPTIONS"],
                    allow_headers=["*"],
                    expose_headers=["mcp-session-id"],
                ),
            ],
            lifespan=lifespan,
        )

        uvicorn.run(
            starlette_app,
            host="0.0.0.0",
            port=int(port),
            log_level=log_level_name.lower(),
        )
    else:
        import tempfile
        logger.info(
            "starting Maeris MCP server",
            mode="stdio",
            log_level=log_level_name,
            log_file=os.path.join(tempfile.gettempdir(), "maeris.log"),
        )
        # Stdio mode
        from mcp.server.stdio import stdio_server

        async def run_stdio():
            async with stdio_server() as streams:
                await server.run(
                    streams[0],
                    streams[1],
                    server.create_initialization_options(),
                )
            write_session_summary()

        asyncio.run(run_stdio())


if __name__ == "__main__":
    main()
