import type { MutationCtx } from "../_generated/server";
import type { Id } from "../_generated/dataModel";
import { nextCode } from "./seq";
import type { ActorLite } from "./access";

export interface AuditInput {
  action: string;
  module: string;
  entityType?: string;
  entityId?: string;
  entityLabel?: string;
  previousValue?: unknown;
  newValue?: unknown;
  reason?: string | null;
  severity?: "INFO" | "WARNING" | "CRITICAL";
  apartmentId?: Id<"apartments"> | null;
  reservationId?: Id<"reservations"> | null;
  customerId?: Id<"customers"> | null;
  /** device context captured by the web layer and passed through mutation args when available */
  client?: { ip?: string | null; device?: string | null; browser?: string | null } | null;
  at?: number;
}

/** Append an immutable audit event (EVT-000123). Never update or delete audit rows. */
export async function audit(ctx: MutationCtx, actor: ActorLite, input: AuditInput): Promise<Id<"auditLog">> {
  const code = await nextCode(ctx, "event");
  return ctx.db.insert("auditLog", {
    code,
    action: input.action,
    module: input.module,
    severity: input.severity ?? "INFO",
    userId: actor?.id,
    userName: actor?.fullName ?? "System",
    roleKey: actor?.roleKey ?? "SYSTEM",
    entityType: input.entityType,
    entityId: input.entityId,
    entityLabel: input.entityLabel,
    previousValue: input.previousValue === undefined ? undefined : JSON.stringify(input.previousValue),
    newValue: input.newValue === undefined ? undefined : JSON.stringify(input.newValue),
    reason: input.reason ?? undefined,
    apartmentId: input.apartmentId ?? undefined,
    reservationId: input.reservationId ?? undefined,
    customerId: input.customerId ?? undefined,
    ipAddress: input.client?.ip ?? undefined,
    device: input.client?.device ?? undefined,
    browser: input.client?.browser ?? undefined,
    sessionId: actor?.sessionId ?? undefined,
    at: input.at ?? Date.now(),
  });
}
