/**
 * メインDB書き込みの監査ログ（`db.write`。`docs/logging-design.md` §6 / 指示書AT §3-7）。
 *
 * ★成功・失敗の両方で1件ずつ出す★。★空パッチ（何も書かない要求）では出さない★（呼び出し側が呼ばない）。
 * ★備考の中身は絶対に載せない★（`comment_changed: boolean` だけ）。
 * ★エラーメッセージは載せない★ — DB のユーザー名が入る（例: 列の権限エラー 1143 の文言）。
 *   載せるのは `dbErrorCode()` が返すコードだけ。
 */
import { logEvent } from "@/lib/logger";
import type { DbWriteLogEvent } from "@/lib/logger/events";

/**
 * 例外から「Prisma のエラーコード」と「ドライバのエラー番号」だけを取り出す（純粋関数）。
 *
 * Prisma 7 + `@prisma/adapter-mariadb` では、DB のエラーは
 * `PrismaClientKnownRequestError`（`code: "P2039"` 等）に包まれ、ドライバの番号は
 * `meta.driverAdapterError.cause.originalCode`（例: `"1143"`）に入る。
 * ★形式に合う値（`P` + 4桁 / 数字だけ）以外は拾わない★（メッセージが紛れ込まないように）。
 *
 * @returns 例: `"P2039:1143"` / `"P2039"` / `"1143"`。何も取れなければ `"unknown"`
 */
export function dbErrorCode(err: unknown): string {
  const parts: string[] = [];
  if (err !== null && typeof err === "object") {
    const record = err as Record<string, unknown>;
    if (typeof record.code === "string" && /^P\d{4}$/.test(record.code)) {
      parts.push(record.code);
    }
    const driverCode = driverErrorNumber(record);
    if (driverCode !== null) parts.push(driverCode);
  }
  return parts.length > 0 ? parts.join(":") : "unknown";
}

function driverErrorNumber(record: Record<string, unknown>): string | null {
  // Prisma に包まれた形: meta.driverAdapterError.cause.originalCode
  const meta = asRecord(record.meta);
  const adapterError = asRecord(meta?.driverAdapterError);
  const cause = asRecord(adapterError?.cause) ?? asRecord(record.cause);
  const candidates: unknown[] = [cause?.originalCode, cause?.code, record.errno];
  for (const candidate of candidates) {
    if (typeof candidate === "number" && Number.isInteger(candidate)) return String(candidate);
    if (typeof candidate === "string" && /^\d+$/.test(candidate)) return candidate;
  }
  return null;
}

function asRecord(value: unknown): Record<string, unknown> | null {
  return value !== null && typeof value === "object" ? (value as Record<string, unknown>) : null;
}

/** `db.write` を1件出す。成功は info、失敗は error（★`err` は渡さない★。メッセージにユーザー名が入るため） */
export function logDbWrite(payload: Omit<DbWriteLogEvent, "event">): void {
  const event: DbWriteLogEvent = { event: "db.write", ...payload };
  if (payload.success) {
    logEvent("info", event);
  } else {
    logEvent("error", event);
  }
}
