# Copyright 2025 Softwell S.r.l.
# Licensed under the Apache License, Version 2.0

"""MCP demo app — exposes calculator and greeting tools via MCP Streamable HTTP.

Routes (via McpApplication JSON-RPC dispatch):
    tools/list  → enumerate available tools
    tools/call  → call a tool by name
    initialize  → server capabilities

Tools exposed:
    calc_add       - Add two numbers
    calc_multiply  - Multiply two numbers
    calc_factorial - Factorial of n
    utils_greet    - Greet by name
"""

from __future__ import annotations

from typing import Any

from genro_asgi import McpApplication
from genro_routes import Router, RoutingClassAuto, route  # type: ignore[import-untyped]


class CalcTools(RoutingClassAuto):
    """Calculator tools — mounted as 'calc' sub-router."""

    @route(description="Add two numbers together")
    def add(self, a: int = 0, b: int = 0) -> dict:
        """Return the sum of a and b."""
        return {"result": a + b}

    @route(description="Multiply two numbers")
    def multiply(self, a: int = 0, b: int = 0) -> dict:
        """Return the product of a and b."""
        return {"result": a * b}

    @route(description="Compute factorial of n")
    def factorial(self, n: int = 1) -> dict:
        """Return n! for non-negative n."""
        if n < 0:
            return {"error": "n must be non-negative"}
        result = 1
        for i in range(2, n + 1):
            result *= i
        return {"result": result}


class UtilTools(RoutingClassAuto):
    """Utility tools — mounted as 'utils' sub-router."""

    @route(description="Greet someone by name")
    def greet(self, name: str = "World") -> dict:
        """Return a greeting message."""
        return {"message": f"Hello, {name}!"}


class Application(McpApplication):
    """MCP demo: calculator + utility tools.

    Run:
        python -m genro_asgi serve examples/mcp_demo

    Test with curl:
        # Initialize
        curl -X POST http://localhost:8000/mcp_demo/ \\
          -H 'Content-Type: application/json' \\
          -d '{"jsonrpc":"2.0","id":1,"method":"initialize"}'

        # List tools
        curl -X POST http://localhost:8000/mcp_demo/ \\
          -H 'Content-Type: application/json' \\
          -d '{"jsonrpc":"2.0","id":2,"method":"tools/list"}'

        # Call calc_add
        curl -X POST http://localhost:8000/mcp_demo/ \\
          -H 'Content-Type: application/json' \\
          -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"calc_add","arguments":{"a":3,"b":4}}}'

        # Call utils_greet
        curl -X POST http://localhost:8000/mcp_demo/ \\
          -H 'Content-Type: application/json' \\
          -d '{"jsonrpc":"2.0","id":4,"method":"tools/call","params":{"name":"utils_greet","arguments":{"name":"Giovanni"}}}'

        # Notification (no id → 202)
        curl -v -X POST http://localhost:8000/mcp_demo/ \\
          -H 'Content-Type: application/json' \\
          -d '{"jsonrpc":"2.0","method":"notifications/initialized"}'
    """

    mcp_name = "mcp-demo"
    mcp_version = "0.1.0"

    def on_init(self, **kwargs: Any) -> None:
        """Setup calculator and utility sub-routers."""
        external_router = Router(self, name="tools")
        external_router.attach_instance(CalcTools(), name="calc")
        external_router.attach_instance(UtilTools(), name="utils")
        self.set_router(external_router)


if __name__ == "__main__":
    app = Application()
    print(f"MCP Demo: {app.mcp_name} v{app.mcp_version}")
    nodes = app._external_router.nodes(forbidden=True)  # type: ignore[union-attr]
    print(f"Router nodes: {nodes}")
