/**
 * T4 · Immutable, append-only, ZERO-payload audit log (INV10). Entries are metadata only —
 * principal, host_id, action, ts, outcome, reason, salted remoteAddrHash. Terminal payload is
 * structurally excluded (no field carries it; `assertZeroPayload` enforces it before every append).
 */
import type { AuditAction, AuditEvent, AuditOutcome, AuthenticatedPrincipal, AuditSink } from '../types.js'
import { AuditEventSchema } from '../types.js'
import { assertZeroPayload } from './redact.js'

export interface BuildAuditArgs {
  readonly action: AuditAction
  readonly principal: AuthenticatedPrincipal | null
  readonly hostId: string | null
  readonly sessionId: string | null
  readonly jti: string | null
  readonly outcome: AuditOutcome
  readonly reason: string
  readonly remoteAddrHash: string
  readonly now: number
}

export function buildAuditEvent(p: BuildAuditArgs): AuditEvent {
  const event: AuditEvent = {
    ts: new Date(p.now * 1000).toISOString(),
    action: p.action,
    principalId: p.principal?.principalId ?? '',
    accountId: p.principal?.accountId ?? '',
    hostId: p.hostId,
    sessionId: p.sessionId,
    jti: p.jti,
    outcome: p.outcome,
    reason: p.reason,
    remoteAddrHash: p.remoteAddrHash,
  }
  AuditEventSchema.parse(event) // strict schema rejects any smuggled extra key (INV10)
  return event
}

/** Append-only (never update/delete). Guarded by `assertZeroPayload` (INV10). */
export async function audit(sink: AuditSink, e: AuditEvent): Promise<void> {
  assertZeroPayload(e)
  await sink.append(e)
}
