/**
 * Audit log producer — tenant-audit-log spec.
 *
 * logAuditEvent(ctx, event): fire-and-forget enqueue to AUDIT_QUEUE.
 * - Applies sensitive-field masking for settings.updated events.
 * - Never writes to Postgres inline — the consumer Worker handles inserts.
 * - Swallows enqueue failures: a failed send MUST NOT throw into the mutation handler.
 *
 * Import path: @zync/db/queries (re-exported via packages/db/src/queries/index.ts).
 */
import type { AuditEvent } from '@zync/types'
import type { Env } from '@zync/types'
import { SENSITIVE_FIELD_BLOCKLIST, REDACTED } from '../constants/audit'

// Minimal context interface — avoids a hono dependency in @zync/db
interface AppContext {
  env: Env
}

/**
 * Mask sensitive field values in `metadata` before enqueueing.
 * Only active for `settings.updated` events.
 *
 * Pattern: metadata may carry `{ field, old_value, new_value }` or a flat map
 * of field→value. Both shapes are handled:
 *   1. If `metadata.field` matches a blocklisted name → redact old_value/new_value.
 *   2. For any other key in metadata whose name is in the blocklist → redact value.
 */
function maskSensitive(event: AuditEvent): AuditEvent {
  if (event.eventType !== 'settings.updated' || !event.metadata) return event

  const meta = { ...event.metadata }

  // Shape 1: { field: string, old_value: unknown, new_value: unknown }
  if (typeof meta['field'] === 'string') {
    const fieldName = meta['field'] as string
    if ((SENSITIVE_FIELD_BLOCKLIST as readonly string[]).includes(fieldName)) {
      meta['old_value'] = REDACTED
      meta['new_value'] = REDACTED
    }
  }

  // Shape 2: arbitrary keys — redact any whose name is in the blocklist
  for (const key of Object.keys(meta)) {
    if ((SENSITIVE_FIELD_BLOCKLIST as readonly string[]).includes(key)) {
      meta[key] = REDACTED
    }
  }

  return { ...event, metadata: meta }
}

/**
 * Enqueue an audit event onto AUDIT_QUEUE (fire-and-forget).
 * The consumer Worker inserts the row into tenant_audit_log.
 */
export async function logAuditEvent(ctx: AppContext, event: AuditEvent): Promise<void> {
  const masked = maskSensitive(event)
  try {
    await ctx.env.AUDIT_QUEUE.send(masked)
  } catch (err) {
    console.error('audit enqueue failed', { eventType: event.eventType, err })
  }
}
