/**
 * Edge Function 通用中间件
 *
 * 用法：
 *   import { withMiddleware } from "../_shared/middleware.ts";
 *
 *   Deno.serve(withMiddleware("my-fn", async (req, ctx) => {
 *     ctx.log("hello");
 *     return ctx.json({ ok: true });
 *   }));
 *
 * 自动处理：CORS 预检、trace_id、统一异常捕获、统一 JSON 响应。
 */

import { handlePreflight } from "./cors.ts";
import { getTraceId, logWithTrace, errorWithTrace } from "./trace.ts";
import { jsonResponse, errorResponse } from "./response.ts";

export interface FnContext {
  traceId: string;
  fnName: string;
  log: (...args: unknown[]) => void;
  error: (...args: unknown[]) => void;
  json: (body: unknown, status?: number) => Response;
  fail: (
    message: string,
    status?: number,
    opts?: { code?: string; details?: unknown },
  ) => Response;
}

export type FnHandler = (req: Request, ctx: FnContext) => Promise<Response> | Response;

export function withMiddleware(fnName: string, handler: FnHandler) {
  return async (req: Request): Promise<Response> => {
    const preflight = handlePreflight(req);
    if (preflight) return preflight;

    const traceId = getTraceId(req);
    const ctx: FnContext = {
      traceId,
      fnName,
      log: (...args) => logWithTrace(traceId, fnName, ...args),
      error: (...args) => errorWithTrace(traceId, fnName, ...args),
      json: (body, status = 200) =>
        jsonResponse(body, status, { "x-trace-id": traceId }),
      fail: (message, status = 500, opts = {}) =>
        errorResponse(message, status, { traceId, ...opts }),
    };

    const startedAt = Date.now();
    try {
      ctx.log(`→ ${req.method} ${new URL(req.url).pathname}`);
      const res = await handler(req, ctx);
      ctx.log(`← ${res.status} (${Date.now() - startedAt}ms)`);
      return res;
    } catch (err) {
      ctx.error("Unhandled exception:", err);
      return ctx.fail(
        err instanceof Error ? err.message : "Internal error",
        500,
        { code: "UNHANDLED_EXCEPTION" },
      );
    }
  };
}
