/**
 * 起動時の初期化ログと、捕捉漏れエラーの記録。
 *
 * `register()` / `onRequestError()` は Next.js 16.3.3 のファイル規約
 * （node_modules/next/dist/docs/01-app/03-api-reference/03-file-conventions/instrumentation.md）
 * に従う。`onRequestError` は v15.0.0 で安定。
 *
 * logger を関数の中で動的 import しているのは、公式ガイドが
 * 「副作用のある import は register() の内側に置く」ことを推奨しており、
 * かつ `register()` が全ランタイムで呼ばれるため。
 * pino は Node.js API に依存するので、トップレベル import にしない。
 *
 * 外部送信（Slack 通知等）は本設計のスコープ外なので追加しない。
 */
import type { Instrumentation } from "next";

/**
 * サーバーインスタンス起動時に1回だけ走る。
 * 「ログ機構が生きていること」と「どの設定で動いているか」を1行残す。
 * これが無いと、ログが出ない原因が LOG_LEVEL なのか未起動なのか切り分けられない。
 */
export async function register(): Promise<void> {
  const { logEvent, logger } = await import("@/lib/logger");
  logEvent("info", {
    event: "app.start",
    log_level: logger.level,
    node_env: process.env.NODE_ENV ?? "unknown",
    next_runtime: process.env.NEXT_RUNTIME ?? "unknown",
  });
}

/**
 * ルートの catch 節で拾えなかったサーバーエラー。
 *
 * `api.error` ではなく `app.uncaught` で記録する。
 * 意図的に処理したエラーと捕捉漏れが同じイベント名で混ざると、
 * 障害調査で「ハンドリング済みか否か」を区別できなくなる。
 */
export const onRequestError: Instrumentation.onRequestError = async (
  error,
  request,
  context
) => {
  const {
    logEvent,
    normalizeRequestId,
    runWithRequestId,
    REQUEST_ID_HEADER,
  } = await import("@/lib/logger");

  // request.path はクエリ文字列を含む（例: /api/clean-logs?facility_name=...）。
  // 施設名などの値が載るため、パス部分だけにする（§4 のマスキング規約）
  const route = request.path.split("?")[0] ?? request.path;

  const digest =
    typeof error === "object" && error !== null && "digest" in error
      ? String((error as { digest: unknown }).digest)
      : undefined;

  const event = {
    event: "app.uncaught",
    route,
    method: request.method,
    route_path: context.routePath,
    router_kind: context.routerKind,
    route_type: context.routeType,
    revalidate_reason: context.revalidateReason,
    error_digest: digest,
  } as const;

  // onRequestError はルートの AsyncLocalStorage の外で走るため、
  // ヘッダから相関IDを取り直す。無ければ mixin が "-" にする
  // （ここで新規生成しても紐づく先が無く、偽の相関を作るだけ）
  const requestId = normalizeRequestId(request.headers[REQUEST_ID_HEADER]);
  if (requestId) {
    runWithRequestId(requestId, () => logEvent("error", event, error));
    return;
  }
  logEvent("error", event, error);
};
