from __future__ import annotations

import json
import logging
import time
from typing import Awaitable, Callable

from aiohttp import web

from .context import get_request_context

Handler = Callable[[web.Request], Awaitable[web.StreamResponse]]
Middleware = Callable[[web.Request, Handler], Awaitable[web.StreamResponse]]


def build_access_log_middleware(logger: logging.Logger | None = None) -> Middleware:
    log = logger or logging.getLogger("ember.gateway.access")

    @web.middleware
    async def access_log_mw(request: web.Request, handler: Handler) -> web.StreamResponse:
        t0 = time.time()
        status = 500
        try:
            resp = await handler(request)
            status = getattr(resp, "status", status)
            return resp
        finally:
            try:
                ctx = get_request_context(request)
                latency_ms = round((time.time() - t0) * 1000.0, 3)
                rec = {
                    "event": "http.access",
                    "method": request.method,
                    "path": request.path,
                    "status": status,
                    "latency_ms": latency_ms,
                    "org_id": getattr(ctx, "org_id", None),
                    "user_agent": request.headers.get("User-Agent"),
                    "client_ip": request.headers.get("X-Forwarded-For") or (request.remote or ""),
                }
                # For chat completions, include simple request hints (no content)
                if request.method == "POST" and request.path == "/v1/chat/completions":
                    body = request.get("json_body") or {}
                    if isinstance(body, dict):
                        rec["stream"] = bool(body.get("stream", False))
                        rec["model"] = body.get("model")
                log.info(json.dumps(rec, separators=(",", ":")))
            except Exception:
                # Never block response on logging issues, but make failures
                # visible so sustained logging breakage is detectable.
                log.debug("Access log serialization failed", exc_info=True)

    return access_log_mw
