"""Minimal ASGI application for server-mode HTTP deployments.

This module provides a concrete import target for runtime commands like:

    python -m cleveragents server serve --app cleveragents.a2a.asgi:app

It intentionally keeps behavior minimal and dependency-free (no FastAPI/
Starlette dependency) while providing the required health probe endpoint
for container and Kubernetes deployments.
"""

from __future__ import annotations

import logging
from collections.abc import Awaitable, Callable

_logger: logging.Logger = logging.getLogger(__name__)

Headers = list[tuple[bytes, bytes]]
SendCallable = Callable[[dict[str, object]], Awaitable[None]]

# Paths recognised by this ASGI app.  Used to distinguish 404 (unknown
# path) from 405 (known path, wrong method) per RFC 9110 S15.5.6.
_KNOWN_PATHS: frozenset[str] = frozenset({"/", "/live", "/ready", "/health"})


async def _send_response(
    send: SendCallable,
    *,
    status: int,
    body: bytes,
    headers: Headers | None = None,
) -> None:
    """Send a complete HTTP response via ASGI ``send``."""
    response_headers: Headers = [
        (b"content-type", b"application/json"),
        (b"content-length", str(len(body)).encode()),
        (b"x-content-type-options", b"nosniff"),
        (b"cache-control", b"no-store"),
    ]
    if headers:
        response_headers.extend(headers)

    await send(
        {
            "type": "http.response.start",
            "status": status,
            "headers": response_headers,
        }
    )
    await send(
        {
            "type": "http.response.body",
            "body": body,
        }
    )


async def app(
    scope: dict[str, object],
    receive: Callable[[], Awaitable[dict[str, object]]],
    send: SendCallable,
) -> None:
    """Serve health and readiness endpoints for Kubernetes probes.

    Supported routes:
    - ``GET /live`` -> ``200`` with ``{"status":"alive"}``
    - ``GET /ready`` -> ``200`` with ``{"status":"ready"}``
    - ``GET /health`` -> ``200`` with ``{"status":"ok"}`` (compat alias)
    - ``GET /`` -> ``200`` with ``{"service":"cleveragents"}``
    - known path, wrong method -> ``405``
    - unknown path -> ``404``
    """
    scope_type = str(scope.get("type", ""))

    if scope_type == "lifespan":
        while True:
            message = await receive()
            message_type = str(message.get("type", ""))
            if message_type == "lifespan.startup":
                await send({"type": "lifespan.startup.complete"})
            elif message_type == "lifespan.shutdown":
                await send({"type": "lifespan.shutdown.complete"})
                return
            else:
                _logger.warning(
                    "Ignoring unrecognised lifespan message type: %s",
                    message_type,
                )

    elif scope_type == "websocket":
        # Consume the websocket.connect event before sending close, per
        # the ASGI WebSocket protocol sequence.
        await receive()
        # Code 1008 (Policy Violation) signals that WebSocket is not
        # supported, rather than 1000 (Normal Closure) which implies success.
        await send({"type": "websocket.close", "code": 1008})
        return

    elif scope_type != "http":
        raise RuntimeError(f"Unsupported ASGI scope type: {scope_type!r}")

    del receive  # No HTTP request-body handling required for these endpoints.

    method = str(scope.get("method", "GET")).upper()
    path = str(scope.get("path", "/"))

    if method == "GET" and path == "/live":
        await _send_response(send, status=200, body=b'{"status":"alive"}')
        return

    if method == "GET" and path == "/ready":
        await _send_response(send, status=200, body=b'{"status":"ready"}')
        return

    if method == "GET" and path == "/health":
        await _send_response(send, status=200, body=b'{"status":"ok"}')
        return

    if method == "GET" and path == "/":
        await _send_response(send, status=200, body=b'{"service":"cleveragents"}')
        return

    # Known path with wrong method -> 405 Method Not Allowed (RFC 9110 S15.5.6)
    if path in _KNOWN_PATHS:
        await _send_response(
            send,
            status=405,
            body=b'{"error":"method not allowed"}',
            headers=[(b"allow", b"GET")],
        )
        return

    await _send_response(send, status=404, body=b'{"error":"not found"}')
