"""Minimal ASGI application that exposes an OpenAI-compatible HTTP endpoint
and forwards requests through a :class:`~deskclaw_client.bridges.Bridge`."""

from __future__ import annotations

import json
import logging
import time
import uuid
from typing import Any

from deskclaw_client.bridges import Bridge

log = logging.getLogger(__name__)


def make_app(bridge: Bridge) -> Any:
    """Return a bare ASGI3 callable wired to *bridge*."""

    async def app(scope: dict, receive: Any, send: Any) -> None:
        if scope["type"] == "lifespan":
            await _handle_lifespan(scope, receive, send, bridge)
            return
        if scope["type"] != "http":
            return

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

        if method == "GET" and path == "/health":
            body = await bridge.health()
            await _json_response(send, 200, body)
        elif method == "POST" and path == "/v1/chat/completions":
            await _handle_chat(receive, send, bridge)
        else:
            await _json_response(send, 404, {"error": "not found"})

    return app


async def _handle_lifespan(
    scope: dict, receive: Any, send: Any, bridge: Bridge
) -> None:
    while True:
        msg = await receive()
        if msg["type"] == "lifespan.startup":
            try:
                await bridge.connect()
                await send({"type": "lifespan.startup.complete"})
            except Exception as exc:
                log.error("Bridge connect failed: %s", exc)
                await send({"type": "lifespan.startup.failed", "message": str(exc)})
                return
        elif msg["type"] == "lifespan.shutdown":
            await bridge.close()
            await send({"type": "lifespan.shutdown.complete"})
            return


async def _handle_chat(receive: Any, send: Any, bridge: Bridge) -> None:
    body_bytes = b""
    while True:
        msg = await receive()
        body_bytes += msg.get("body", b"")
        if not msg.get("more_body", False):
            break

    try:
        payload = json.loads(body_bytes)
    except (json.JSONDecodeError, ValueError):
        await _json_response(send, 400, {"error": "invalid JSON body"})
        return

    messages = payload.get("messages", [])
    if not messages:
        await _json_response(send, 400, {"error": "messages field is required"})
        return

    t0 = time.monotonic()
    try:
        result = await bridge.chat(
            messages,
            model=payload.get("model", ""),
            temperature=payload.get("temperature", 1.0),
            max_tokens=payload.get("max_tokens"),
        )
    except Exception as exc:
        log.exception("Bridge chat error")
        await _json_response(
            send,
            502,
            {
                "error": {
                    "message": str(exc),
                    "type": "bridge_error",
                    "code": "bridge_failure",
                }
            },
        )
        return

    elapsed_ms = (time.monotonic() - t0) * 1000
    log.info(
        "Chat completed in %.0fms (model=%s, messages=%d)",
        elapsed_ms,
        payload.get("model", "?"),
        len(messages),
    )

    if "id" not in result:
        result["id"] = f"chatcmpl-{uuid.uuid4().hex[:12]}"

    await _json_response(send, 200, result)


async def _json_response(send: Any, status: int, body: dict) -> None:
    payload = json.dumps(body).encode()
    await send(
        {
            "type": "http.response.start",
            "status": status,
            "headers": [
                [b"content-type", b"application/json"],
                [b"content-length", str(len(payload)).encode()],
            ],
        }
    )
    await send({"type": "http.response.body", "body": payload})
