"""SSE Polling Demo Server

Demonstrates the SSE polling pattern with close_sse_stream() for long-running tasks.

Features demonstrated:
- Priming events (automatic with EventStore)
- Server-initiated stream close via close_sse_stream callback
- Client auto-reconnect with Last-Event-ID
- Progress notifications during long-running tasks

Run with:
    uv run mcp-sse-polling-demo --port 3000
"""

import logging

import anyio
import click
import mcp_types as types
import uvicorn
from mcp.server import Server, ServerRequestContext

from .event_store import InMemoryEventStore

logger = logging.getLogger(__name__)


async def handle_list_tools(
    ctx: ServerRequestContext, params: types.PaginatedRequestParams | None
) -> types.ListToolsResult:
    """List available tools."""
    return types.ListToolsResult(
        tools=[
            types.Tool(
                name="process_batch",
                description=(
                    "Process a batch of items with periodic checkpoints. "
                    "Demonstrates SSE polling where server closes stream periodically."
                ),
                input_schema={
                    "type": "object",
                    "properties": {
                        "items": {
                            "type": "integer",
                            "description": "Number of items to process (1-100)",
                            "default": 10,
                        },
                        "checkpoint_every": {
                            "type": "integer",
                            "description": "Close stream after this many items (1-20)",
                            "default": 3,
                        },
                    },
                },
            )
        ]
    )


async def handle_call_tool(ctx: ServerRequestContext, params: types.CallToolRequestParams) -> types.CallToolResult:
    """Handle tool calls."""
    arguments = params.arguments or {}

    if params.name == "process_batch":
        items = arguments.get("items", 10)
        checkpoint_every = arguments.get("checkpoint_every", 3)

        if items < 1 or items > 100:
            return types.CallToolResult(
                content=[types.TextContent(type="text", text="Error: items must be between 1 and 100")]
            )
        if checkpoint_every < 1 or checkpoint_every > 20:
            return types.CallToolResult(
                content=[types.TextContent(type="text", text="Error: checkpoint_every must be between 1 and 20")]
            )

        await ctx.session.send_log_message(  # pyright: ignore[reportDeprecated]
            level="info",
            data=f"Starting batch processing of {items} items...",
            logger="process_batch",
            related_request_id=ctx.request_id,
        )

        for i in range(1, items + 1):
            # Simulate work
            await anyio.sleep(0.5)

            # Report progress
            await ctx.session.send_log_message(  # pyright: ignore[reportDeprecated]
                level="info",
                data=f"[{i}/{items}] Processing item {i}",
                logger="process_batch",
                related_request_id=ctx.request_id,
            )

            # Checkpoint: close stream to trigger client reconnect
            if i % checkpoint_every == 0 and i < items:
                await ctx.session.send_log_message(  # pyright: ignore[reportDeprecated]
                    level="info",
                    data=f"Checkpoint at item {i} - closing SSE stream for polling",
                    logger="process_batch",
                    related_request_id=ctx.request_id,
                )
                if ctx.close_sse_stream:
                    logger.info(f"Closing SSE stream at checkpoint {i}")
                    await ctx.close_sse_stream()
                # Wait for client to reconnect (must be > retry_interval of 100ms)
                await anyio.sleep(0.2)

        return types.CallToolResult(
            content=[
                types.TextContent(
                    type="text",
                    text=f"Successfully processed {items} items with checkpoints every {checkpoint_every} items",
                )
            ]
        )

    return types.CallToolResult(content=[types.TextContent(type="text", text=f"Unknown tool: {params.name}")])


@click.command()
@click.option("--port", default=3000, help="Port to listen on")
@click.option(
    "--log-level",
    default="INFO",
    help="Logging level (DEBUG, INFO, WARNING, ERROR)",
)
@click.option(
    "--retry-interval",
    default=100,
    help="SSE retry interval in milliseconds (sent to client)",
)
def main(port: int, log_level: str, retry_interval: int) -> int:
    """Run the SSE Polling Demo server."""
    logging.basicConfig(
        level=getattr(logging, log_level.upper()),
        format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
    )

    app = Server(
        "sse-polling-demo",
        on_list_tools=handle_list_tools,
        on_call_tool=handle_call_tool,
    )

    starlette_app = app.streamable_http_app(
        event_store=InMemoryEventStore(),
        retry_interval=retry_interval,
        debug=True,
    )

    logger.info(f"SSE Polling Demo server starting on port {port}")
    logger.info("Try: POST /mcp with tools/call for 'process_batch'")
    uvicorn.run(starlette_app, host="127.0.0.1", port=port)
    return 0


if __name__ == "__main__":
    main()
