"""Bernstein MCP server.

Exposes Bernstein's orchestration layer as MCP tools so any MCP client
(Cursor, Claude Code, Cline, Windsurf, …) can drive multi-agent work
through Bernstein.

Transport:
    stdio  — for local IDE integration (default ``bernstein mcp``)
    sse    — for remote/web integration (``bernstein mcp --transport sse``)

Tools:
    bernstein_run     — start an orchestration run with a goal
    bernstein_status  — get task counts summary
    bernstein_tasks   — list tasks with optional status filter
    bernstein_cost    — get cost summary across all roles
    bernstein_stop    — graceful shutdown (writes SHUTDOWN signal)
    bernstein_approve — approve a pending/blocked task
"""

from __future__ import annotations

import json
from pathlib import Path
from typing import Any

import httpx
from mcp.server.fastmcp import FastMCP

_DEFAULT_SERVER_URL = "http://127.0.0.1:8052"


def create_mcp_server(
    server_url: str = _DEFAULT_SERVER_URL,
    name: str = "bernstein",
) -> FastMCP[None]:
    """Build and return the Bernstein FastMCP server instance.

    Args:
        server_url: Base URL of the Bernstein task server.
        name: MCP server name advertised to clients.

    Returns:
        Configured FastMCP instance with all Bernstein tools registered.
    """
    mcp: FastMCP[None] = FastMCP(name)

    # ------------------------------------------------------------------
    # bernstein_run
    # ------------------------------------------------------------------

    @mcp.tool()
    async def bernstein_run(  # pyright: ignore[reportUnusedFunction]
        goal: str,
        role: str = "backend",
        priority: int = 2,
        scope: str = "medium",
        complexity: str = "medium",
        estimated_minutes: int = 30,
    ) -> str:
        """Start an orchestration run by posting a task to the Bernstein server.

        Args:
            goal: Description of what you want Bernstein to accomplish.
            role: Specialist role to assign (backend, frontend, qa, security, …).
            priority: 1=critical, 2=normal, 3=nice-to-have.
            scope: Task scope — small, medium, or large.
            complexity: Task complexity — low, medium, or high.
            estimated_minutes: Rough time estimate in minutes.

        Returns:
            JSON with the created task ID, title, and status.
        """
        payload: dict[str, Any] = {
            "title": goal[:120],
            "description": goal,
            "role": role,
            "priority": priority,
            "scope": scope,
            "complexity": complexity,
            "estimated_minutes": estimated_minutes,
        }
        async with httpx.AsyncClient() as client:
            resp = await client.post(f"{server_url}/tasks", json=payload)
            resp.raise_for_status()
            data: dict[str, Any] = resp.json()
        return json.dumps(
            {"task_id": data["id"], "title": data["title"], "status": data["status"]},
            indent=2,
        )

    # ------------------------------------------------------------------
    # bernstein_status
    # ------------------------------------------------------------------

    @mcp.tool()
    async def bernstein_status(  # pyright: ignore[reportUnusedFunction]
    ) -> str:
        """Return a summary of all task counts from the Bernstein server.

        Returns:
            JSON with total, open, claimed, done, failed counts plus
            a per-role breakdown.
        """
        async with httpx.AsyncClient() as client:
            resp = await client.get(f"{server_url}/status")
            resp.raise_for_status()
            data: dict[str, Any] = resp.json()
        return json.dumps(data, indent=2)

    # ------------------------------------------------------------------
    # bernstein_tasks
    # ------------------------------------------------------------------

    @mcp.tool()
    async def bernstein_tasks(  # pyright: ignore[reportUnusedFunction]
        status: str | None = None,
    ) -> str:
        """List tasks from the Bernstein server.

        Args:
            status: Optional filter — open, claimed, in_progress, done,
                failed, blocked, or cancelled.

        Returns:
            JSON array of task objects.
        """
        params: dict[str, str] = {}
        if status:
            params["status"] = status
        async with httpx.AsyncClient() as client:
            resp = await client.get(f"{server_url}/tasks", params=params)
            resp.raise_for_status()
            data: list[dict[str, Any]] = resp.json()
        return json.dumps(data, indent=2)

    # ------------------------------------------------------------------
    # bernstein_cost
    # ------------------------------------------------------------------

    @mcp.tool()
    async def bernstein_cost(  # pyright: ignore[reportUnusedFunction]
    ) -> str:
        """Return cost summary (total USD spent and per-role breakdown).

        Returns:
            JSON with total_cost_usd and per-role cost breakdown.
        """
        async with httpx.AsyncClient() as client:
            resp = await client.get(f"{server_url}/status")
            resp.raise_for_status()
            data: dict[str, Any] = resp.json()
        per_role_raw: list[dict[str, Any]] = data.get("per_role", [])
        cost_summary: dict[str, Any] = {
            "total_cost_usd": data.get("total_cost_usd", 0.0),
            "per_role": [{"role": r["role"], "cost_usd": r.get("cost_usd", 0.0)} for r in per_role_raw],
        }
        return json.dumps(cost_summary, indent=2)

    # ------------------------------------------------------------------
    # bernstein_stop
    # ------------------------------------------------------------------

    @mcp.tool()
    async def bernstein_stop(  # pyright: ignore[reportUnusedFunction]
        workdir: str = ".",
    ) -> str:
        """Request a graceful Bernstein shutdown by writing a SHUTDOWN signal.

        Writes ``.sdd/runtime/signals/SHUTDOWN`` in the project directory,
        which the orchestrator detects and shuts down gracefully.

        Args:
            workdir: Project root directory (default: current directory).

        Returns:
            Confirmation message.
        """
        signals_dir = Path(workdir) / ".sdd" / "runtime" / "signals"
        signals_dir.mkdir(parents=True, exist_ok=True)
        shutdown_file = signals_dir / "SHUTDOWN"
        shutdown_file.write_text("mcp-stop\n", encoding="utf-8")
        return json.dumps({"status": "shutdown signal sent", "path": str(shutdown_file)})

    # ------------------------------------------------------------------
    # bernstein_approve
    # ------------------------------------------------------------------

    @mcp.tool()
    async def bernstein_approve(  # pyright: ignore[reportUnusedFunction]
        task_id: str,
        note: str = "Approved via MCP",
    ) -> str:
        """Approve a pending or blocked task, marking it complete.

        This is used for approval gates — when a task is awaiting human
        sign-off before proceeding.

        Args:
            task_id: ID of the task to approve.
            note: Optional approval note recorded as the result summary.

        Returns:
            JSON with the updated task status.
        """
        payload: dict[str, Any] = {"result_summary": note}
        async with httpx.AsyncClient() as client:
            resp = await client.post(f"{server_url}/tasks/{task_id}/complete", json=payload)
            resp.raise_for_status()
            data: dict[str, Any] = resp.json()
        return json.dumps(
            {"task_id": data["id"], "status": data["status"], "result_summary": data.get("result_summary")},
            indent=2,
        )

    return mcp


def run_stdio(server_url: str = _DEFAULT_SERVER_URL) -> None:
    """Start the MCP server in stdio transport mode (for local IDE integration).

    Args:
        server_url: Bernstein task server URL.
    """
    mcp = create_mcp_server(server_url=server_url)
    mcp.run(transport="stdio")


def run_sse(server_url: str = _DEFAULT_SERVER_URL, host: str = "127.0.0.1", port: int = 8053) -> None:
    """Start the MCP server in SSE transport mode (for remote/web integration).

    Args:
        server_url: Bernstein task server URL.
        host: Host to bind the SSE server to.
        port: Port to bind the SSE server to.
    """
    mcp = create_mcp_server(server_url=server_url)
    import uvicorn

    uvicorn.run(mcp.sse_app(), host=host, port=port)
