import { sql } from "kysely";
import { createLogger } from "../logger/index.js";
const logger = createLogger("shared").child({ component: "indexers" });
const MAX_MESSAGE_LENGTH = 4096;
const MAX_DELETE_BATCH = 5e3;
const MAX_LOGS_PER_SOURCE = 1e4;
function truncate(input, limit) {
  if (!input) return null;
  return input.length > limit ? `${input.slice(0, limit - 3)}...` : input;
}
function safeJson(value) {
  if (value === void 0) return null;
  try {
    return JSON.parse(JSON.stringify(value));
  } catch {
    if (value == null) return null;
    if (typeof value === "object") {
      return { note: "unserializable", asString: String(value) };
    }
    return value;
  }
}
function pickDb(deps) {
  if (deps.db) return deps.db;
  if (deps.em) {
    try {
      return deps.em.getKysely();
    } catch {
      return null;
    }
  }
  return null;
}
function isInactiveTransactionError(error) {
  const message = error instanceof Error ? error.message : String(error ?? "");
  return /transaction is already (committed|rolled back)/i.test(message);
}
async function pruneExcessLogs(db, source) {
  const rows = await db.selectFrom("indexer_status_logs").select("id").where("source", "=", source).orderBy("occurred_at", "desc").orderBy("id", "desc").offset(MAX_LOGS_PER_SOURCE).limit(MAX_DELETE_BATCH).execute();
  if (!rows.length) return;
  const ids = rows.map((row) => row.id).filter(Boolean);
  if (!ids.length) return;
  await db.deleteFrom("indexer_status_logs").where("id", "in", ids).execute();
}
async function recordIndexerLog(deps, input) {
  const db = pickDb(deps);
  if (!db) {
    logger.warn("Unable to record indexer log (missing db connection)", {
      source: input.source,
      handler: input.handler
    });
    return;
  }
  const level = input.level === "warn" ? "warn" : "info";
  const message = truncate(input.message, MAX_MESSAGE_LENGTH) ?? "\u2014";
  const details = safeJson(input.details);
  const occurredAt = /* @__PURE__ */ new Date();
  try {
    await db.insertInto("indexer_status_logs").values({
      source: input.source,
      handler: input.handler,
      level,
      entity_type: input.entityType ?? null,
      record_id: input.recordId ?? null,
      tenant_id: input.tenantId ?? null,
      organization_id: input.organizationId ?? null,
      message,
      details: details === null ? null : sql`${JSON.stringify(details)}::jsonb`,
      occurred_at: occurredAt
    }).execute();
  } catch (error) {
    if (!isInactiveTransactionError(error)) {
      logger.error("Failed to persist indexer log", { err: error });
    }
    return;
  }
  try {
    await pruneExcessLogs(db, input.source);
  } catch (pruneError) {
    if (!isInactiveTransactionError(pruneError)) {
      logger.warn("Failed to prune indexer logs", { err: pruneError });
    }
  }
}
export {
  recordIndexerLog
};
//# sourceMappingURL=status-log.js.map
