import {
  COMMUNITY_LIMITS,
  hasFeature
} from "./chunk-2N2KL4KM.js";
import {
  effectiveTenant
} from "./chunk-3F6VNSRK.js";
import {
  init_ids,
  newId
} from "./chunk-F4WUVOLE.js";
import {
  init_clock,
  nowMs,
  toIso
} from "./chunk-HFDLUBWN.js";
import {
  getDb,
  init_client
} from "./chunk-TLEKKGH7.js";

// src/db/audit.ts
init_client();
init_ids();
init_clock();
function hydrate(row) {
  let metadata = null;
  if (row.metadata_json) {
    try {
      metadata = JSON.parse(row.metadata_json);
    } catch {
      metadata = null;
    }
  }
  return {
    id: row.id,
    created_at: toIso(row.created_at),
    actor_key_id: row.actor_key_id,
    actor_name: row.actor_name,
    tenant_id: row.tenant_id,
    action: row.action,
    resource_type: row.resource_type,
    resource_id: row.resource_id,
    outcome: row.outcome,
    metadata
  };
}
function recordAudit(input) {
  try {
    const db = getDb();
    const id = newId("audit");
    db.prepare(
      `INSERT INTO audit_log (
         id, created_at, actor_key_id, actor_name, tenant_id,
         action, resource_type, resource_id, outcome, metadata_json
       ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
    ).run(
      id,
      nowMs(),
      input.auth?.keyId ?? null,
      input.auth?.name ?? null,
      // Tenant resolution: explicit `input.tenant_id` wins (admin
      // handlers that act on a specific tenant pass it explicitly).
      // Otherwise route through `effectiveTenant()` so that the
      // `x-agentstep-tenant` header is honored — without this, a
      // product-initiated action on behalf of tenant X would audit as
      // null/global (the service key's own home tenant).
      input.tenant_id !== void 0 ? input.tenant_id : input.auth ? effectiveTenant(input.auth) : null,
      input.action,
      input.resource_type ?? null,
      input.resource_id ?? null,
      input.outcome ?? "success",
      input.metadata ? JSON.stringify(input.metadata) : null
    );
  } catch (err) {
    console.warn("[audit] failed to record entry:", err);
  }
}
function listAudit(opts) {
  const db = getDb();
  const limit = Math.min(Math.max(opts.limit ?? 100, 1), 500);
  const clauses = [];
  const params = [];
  if (opts.tenantFilter != null) {
    clauses.push("tenant_id = ?");
    params.push(opts.tenantFilter);
  }
  if (opts.action) {
    clauses.push("action = ?");
    params.push(opts.action);
  }
  if (opts.actor_key_id) {
    clauses.push("actor_key_id = ?");
    params.push(opts.actor_key_id);
  }
  if (opts.outcome) {
    clauses.push("outcome = ?");
    params.push(opts.outcome);
  }
  if (opts.resource_type) {
    clauses.push("resource_type = ?");
    params.push(opts.resource_type);
  }
  if (opts.resource_id) {
    clauses.push("resource_id = ?");
    params.push(opts.resource_id);
  }
  if (opts.createdGte != null) {
    clauses.push("created_at >= ?");
    params.push(opts.createdGte);
  }
  if (opts.createdLte != null) {
    clauses.push("created_at <= ?");
    params.push(opts.createdLte);
  }
  if (!hasFeature("unlimited_audit") && opts.createdGte == null) {
    const cutoff = nowMs() - COMMUNITY_LIMITS.auditRetentionMs;
    clauses.push("created_at >= ?");
    params.push(cutoff);
  }
  if (opts.cursor) {
    const anchor = db.prepare(`SELECT created_at FROM audit_log WHERE id = ?`).get(opts.cursor);
    if (anchor) {
      clauses.push("(created_at < ? OR (created_at = ? AND id < ?))");
      params.push(anchor.created_at, anchor.created_at, opts.cursor);
    } else {
      clauses.push("id < ?");
      params.push(opts.cursor);
    }
  }
  const where = clauses.length ? `WHERE ${clauses.join(" AND ")}` : "";
  const rows = db.prepare(`SELECT * FROM audit_log ${where} ORDER BY created_at DESC, id DESC LIMIT ?`).all(...params, limit);
  return rows.map(hydrate);
}

export {
  recordAudit,
  listAudit
};
