"""cube-agent — thin local MCP agent.

Presents a unified tool surface to the MCP client. Each tool is routed to
either local execution or proxied to cube-cloud transparently.

Local tools (only needs Docker for builds):
- build_and_publish_to_apollo: Docker buildx + pure Python chart packaging + OCI push
- app_proxy / app_proxy_stop / app_proxy_status: tunnel via cube-cloud (Phase 4)

Remote tools (proxied to cube-cloud):
- All Apollo environment/entity management tools
- Server-side kubectl/Teleport tools

Auth tools (local):
- agent_login / agent_logout / agent_status
"""

from __future__ import annotations

import asyncio
import logging
import sys

from mcp.server import stdio
from mcp.server.lowlevel import Server
from mcp.types import TextContent, Tool

from cube_agent.auth.login import login, login_browser, logout, status as auth_status
from cube_agent.local.build_pipeline import build_and_publish
from cube_agent.local.kube_login import kube_login
from cube_agent.remote.client import CloudClient, CloudClientError
from cube_agent.remote.proxy_tools import REMOTE_TOOL_NAMES, REMOTE_TOOLS
from cube_agent.tunnel.agent_tunnel import start_proxy, stop_proxy, proxy_status

logger = logging.getLogger(__name__)

mcp_server = Server("cube-agent")

# ---------------------------------------------------------------------------
# Local-only tools
# ---------------------------------------------------------------------------

LOCAL_TOOLS: list[Tool] = [
    Tool(
        name="build_and_publish_to_apollo",
        description=(
            "Build and publish an app to Apollo Container Registry. "
            "Builds Docker image locally, packages Helm chart (pure Python), "
            "pushes to OCI registry, and publishes manifest via cube-cloud."
        ),
        inputSchema={
            "type": "object",
            "properties": {
                "chart_path": {
                    "type": "string",
                    "description": "Path to chart directory or Chart.yaml (auto-detected if not specified).",
                },
                "version": {
                    "type": "string",
                    "description": 'Exact version to use (e.g., "1.0.0"). If not specified, bumps current version.',
                },
                "bump": {
                    "type": "string",
                    "description": 'Version bump type: "patch" (default), "minor", or "major".',
                    "default": "patch",
                },
                "app_version": {
                    "type": "string",
                    "description": "New appVersion for Docker image tag. If not specified, uses chart version.",
                },
                "skip_docker": {
                    "type": "boolean",
                    "description": "Skip Docker build/push even if Dockerfile exists.",
                    "default": False,
                },
                "dry_run": {
                    "type": "boolean",
                    "description": "Show what would be done without actually doing it.",
                    "default": False,
                },
            },
        },
    ),
    # Phase 4: App proxy tunnel tools
    Tool(
        name="app_proxy",
        description=(
            "Start a local proxy for a Teleport app via cube-cloud tunnel. "
            "Creates a local TCP listener that tunnels traffic to the remote app "
            "through cube-cloud's WebSocket relay. No tsh needed locally."
        ),
        inputSchema={
            "type": "object",
            "properties": {
                "app": {
                    "type": "string",
                    "description": "App name (from app_list).",
                },
                "port": {
                    "type": "integer",
                    "description": "Local port to listen on (auto-assigned if not specified).",
                },
            },
            "required": ["app"],
        },
    ),
    Tool(
        name="app_proxy_stop",
        description="Stop a running app proxy tunnel.",
        inputSchema={
            "type": "object",
            "properties": {
                "app": {
                    "type": "string",
                    "description": "App name to stop. If not specified, stops all proxies.",
                },
            },
        },
    ),
    Tool(
        name="app_proxy_status",
        description="Show status of running app proxy tunnels.",
        inputSchema={"type": "object", "properties": {}},
    ),
    # Auth tools
    Tool(
        name="agent_login",
        description="Authenticate cube-agent with an API key (for service accounts / CI).",
        inputSchema={
            "type": "object",
            "properties": {
                "api_key": {
                    "type": "string",
                    "description": "API key for cube-cloud authentication.",
                },
            },
            "required": ["api_key"],
        },
    ),
    Tool(
        name="agent_login_browser",
        description="Authenticate via browser login (opens sign-in page, auto-provisions API key).",
        inputSchema={"type": "object", "properties": {}},
    ),
    Tool(
        name="agent_logout",
        description="Remove stored cube-agent API key.",
        inputSchema={"type": "object", "properties": {}},
    ),
    Tool(
        name="agent_status",
        description="Check cube-agent authentication and connectivity status.",
        inputSchema={"type": "object", "properties": {}},
    ),
]

LOCAL_TOOL_NAMES = {t.name for t in LOCAL_TOOLS}


# ---------------------------------------------------------------------------
# Tool listing — unified surface
# ---------------------------------------------------------------------------


@mcp_server.list_tools()
async def list_tools() -> list[Tool]:
    return REMOTE_TOOLS + LOCAL_TOOLS


# ---------------------------------------------------------------------------
# Tool dispatch
# ---------------------------------------------------------------------------


@mcp_server.call_tool()
async def call_tool(name: str, arguments: dict) -> list[TextContent]:
    try:
        result = await _dispatch(name, arguments)
    except Exception as e:
        result = f"Error: {e}"
    return [TextContent(type="text", text=result)]


async def _dispatch(name: str, args: dict) -> str:
    # Local tools — executed in-process
    if name == "build_and_publish_to_apollo":
        return await build_and_publish(
            chart_path=args.get("chart_path"),
            version=args.get("version"),
            bump=args.get("bump", "patch"),
            app_version=args.get("app_version"),
            skip_docker=args.get("skip_docker", False),
            dry_run=args.get("dry_run", False),
        )

    # Phase 4: App proxy tunnel (local TCP listener + WebSocket relay)
    if name == "app_proxy":
        return await start_proxy(args["app"], args.get("port"))
    if name == "app_proxy_stop":
        return await stop_proxy(args.get("app"))
    if name == "app_proxy_status":
        return await proxy_status()

    # Cluster login (local — merges kubeconfig into ~/.kube/config)
    if name == "cube_cluster_login":
        return await kube_login(args["cluster"])

    # Auth tools
    if name == "agent_login":
        return login(args["api_key"])
    if name == "agent_login_browser":
        return await login_browser()
    if name == "agent_logout":
        return logout()
    if name == "agent_status":
        lines = [auth_status()]
        async with CloudClient() as cloud:
            try:
                await cloud.call_tool("list_environments", {"search": "__ping__"})
                lines.append("cube-cloud: connected")
            except CloudClientError as e:
                lines.append(f"cube-cloud: {e}")
            except Exception:
                lines.append("cube-cloud: unreachable")
        return "\n".join(lines)

    # Remote tools — proxy to cube-cloud
    if name in REMOTE_TOOL_NAMES:
        async with CloudClient() as cloud:
            return await cloud.call_tool(name, args)

    return f"Unknown tool: {name}"


# ---------------------------------------------------------------------------
# Entry points
# ---------------------------------------------------------------------------


def cli():
    """Entry point for the cube-agent CLI (stdio MCP server)."""
    logging.basicConfig(level=logging.INFO, stream=sys.stderr)

    async def run():
        async with stdio.stdio_server() as (read_stream, write_stream):
            await mcp_server.run(
                read_stream,
                write_stream,
                mcp_server.create_initialization_options(),
            )

    asyncio.run(run())


if __name__ == "__main__":
    cli()
