#!/usr/bin/env python3
"""
Multi-tenant FastAPI + MCP server that exposes isolated tenant routes
from a single parent app.
"""

import argparse
import sys
from contextlib import AsyncExitStack, asynccontextmanager

import uvicorn
from fastapi import FastAPI
from fastapi.middleware.cors import CORSMiddleware

from ..core import TenantConfig, load_multi_tenant_config_from_yaml
from .server import MCPPlusAPIServer


class MultiTenantMCPServer:
    """Serves multiple isolated tenants from a single FastAPI app.

    Each tenant gets:
    - Its own MCPPlusAPIServer instance
    - Its own internal MCP port
    - Routes mounted at /{tenant_name}/
    """

    def __init__(
        self,
        server_name: str,
        server_description: str,
        tenants: list[TenantConfig],
        max_workers: int = 4,
        base_mcp_port: int = 9001,
    ):
        self.server_name = server_name
        self.server_description = server_description
        self.tenant_configs = tenants
        self.tenants: dict[str, MCPPlusAPIServer] = {}

        self._build_tenants(max_workers=max_workers, base_mcp_port=base_mcp_port)
        self.app = self._create_app()

    def _build_tenants(self, max_workers: int, base_mcp_port: int) -> None:
        seen_names: set[str] = set()
        for offset, tenant in enumerate(self.tenant_configs):
            if not tenant.name:
                raise ValueError("Tenant name cannot be empty")
            if tenant.name in seen_names:
                raise ValueError(f"Duplicate tenant name: {tenant.name}")
            seen_names.add(tenant.name)

            mcp_port = base_mcp_port + offset
            tenant_server = MCPPlusAPIServer(
                server_name=tenant.name,
                server_description=tenant.description,
                indices=tenant.indices,
                max_workers=max_workers,
                mcp_mount_path="/mcp",
                mcp_internal_port=mcp_port,
                copy_middleware=False,
            )
            self.tenants[tenant.name] = tenant_server

    def _create_app(self) -> FastAPI:
        @asynccontextmanager
        async def multi_tenant_lifespan(app: FastAPI):
            async with AsyncExitStack() as stack:
                for tenant_server in self.tenants.values():
                    await stack.enter_async_context(
                        tenant_server.app.router.lifespan_context(tenant_server.app)
                    )
                yield

        app = FastAPI(
            title=self.server_name,
            description=self.server_description,
            version="1.0.0",
            lifespan=multi_tenant_lifespan,
        )

        # Add CORS once at the parent level
        app.add_middleware(
            CORSMiddleware,
            allow_origins=["*"],
            allow_credentials=True,
            allow_methods=["*"],
            allow_headers=["*"],
        )

        # Mount each tenant app at /{tenant_name}
        for tenant_name, tenant_server in self.tenants.items():
            app.mount(f"/{tenant_name}", tenant_server.app)

        @app.get("/")
        async def root_health():
            return {
                "status": "ok",
                "tenants": [
                    {
                        "name": tenant.name,
                        "description": tenant.description,
                    }
                    for tenant in self.tenant_configs
                ],
            }

        @app.get("/tenants")
        async def list_tenants():
            return [
                {
                    "name": tenant.name,
                    "description": tenant.description,
                }
                for tenant in self.tenant_configs
            ]

        return app

    def run(self, host: str = "0.0.0.0", port: int = 8000, **kwargs):
        print(f"Starting multi-tenant server on {host}:{port}")
        print(f"Tenants: {list(self.tenants.keys())}")
        uvicorn.run(self.app, host=host, port=port, **kwargs)


def main() -> int:
    parser = argparse.ArgumentParser(
        description="Multi-tenant search API + MCP server"
    )
    parser.add_argument("--config", required=True, help="Path to YAML configuration")
    parser.add_argument("--host", default="0.0.0.0", help="Host for HTTP server")
    parser.add_argument("--port", type=int, default=8000, help="Port for HTTP server")
    parser.add_argument(
        "--workers",
        type=int,
        default=4,
        help="Number of worker threads for search operations",
    )
    parser.add_argument(
        "--base-mcp-port",
        type=int,
        default=9001,
        help="Base internal MCP port (default: 9001)",
    )
    parser.add_argument(
        "--reload", action="store_true", help="Enable auto-reload for development"
    )

    args = parser.parse_args()

    try:
        server_name, server_description, tenants, server_config = (
            load_multi_tenant_config_from_yaml(args.config)
        )
        host = server_config.get("host", args.host)
        port = server_config.get("port", args.port)
        max_workers = server_config.get("max_workers", args.workers)
        base_mcp_port = server_config.get("base_mcp_port", args.base_mcp_port)

        server = MultiTenantMCPServer(
            server_name=server_name,
            server_description=server_description,
            tenants=tenants,
            max_workers=max_workers,
            base_mcp_port=base_mcp_port,
        )
        server.run(host=host, port=port, reload=args.reload)
    except Exception as exc:
        print(f"Error starting multi-tenant server: {exc}", file=sys.stderr)
        return 1

    return 0


if __name__ == "__main__":
    sys.exit(main())
