/**
 * Closed enum of audited actions per DPA. New action types require an
 * explicit type bump — compliance auditors sample by enum value.
 */
export type AuditAction =
  | "VIEW"
  | "CREATE"
  | "UPDATE"
  | "DELETE"
  | "EXPORT"
  | "PERMISSION_CHANGE"
  | "CONSENT_GRANT"
  | "CONSENT_WITHDRAW"
  | "RESTRICT"
  | "UNRESTRICT";

/**
 * `from_where` fragment per DPA. IP truncated to /24 (IPv4) or /48 (IPv6)
 * before storage; use `truncateIp(rawIp)` to enforce. For non-HTTP contexts,
 * sentinels are conventional: `{ ipTruncated: "system", userAgent: "background-job" }`.
 */
export type AuditFrom = {
  ipTruncated: string;
  userAgent: string;
};

/**
 * Universal audit entry. By construction, this type has NO `payload`/`body`/
 * `oldValue`/`newValue` fields — the DPA "what NOT to log" exclusion list is
 * enforced by the type itself. UPDATE actions capture field NAMES only
 * (`changedFields`); per-collection value capture is a separate API (out of
 * scope for v1).
 */
export type AuditEntry = {
  // WHO
  /** User id, or "system"/"service-{name}" for non-user actors. NEVER email or name. */
  actorId: string;
  actorType: "user" | "system" | "service";
  /** Snapshot of actor's roles AT TIME OF ACTION — preserves historical state. */
  actorRoles: string[];

  // WHAT
  action: AuditAction;
  resource: { type: string; id?: string };
  /** UPDATE only: names of fields that changed (NOT values — PII risk). */
  changedFields?: string[];

  // WHEN
  /** Server time. Sinks serialize as ISO 8601. */
  at: Date;

  // SCOPE (where)
  scope: {
    feature: string;
    environment: string;
    /** Required field. Single-tenant projects use "default" as the sentinel. */
    tenant: string;
  };

  // WHY
  reason?: string;
  /** OTel trace ID. Auto-populated by `TraceIdEnrichingAuditLog` decorator at bind time. */
  correlationId?: string;
  requestId?: string;

  // FROM (per DPA)
  from: AuditFrom;

  // PII CLASSIFICATION
  /** Caller MUST declare. Drives downstream retention/access policies. */
  containsPii: boolean;
  /**
   * Free-form list. Conventions (suggested, not enforced): "email", "name",
   * "phone", "address", "ssn", "financial", "health". Free-form because
   * regulatory categories differ by jurisdiction.
   */
  piiCategories?: string[];

  // OUTCOME
  outcome: "success" | "denied" | "error";
  errorCode?: string;
};
