/**
 * lib/fk-allowlist.ts — Identity/audit columns intentionally NOT foreign keys.
 *
 * RULE (non-negotiable): every column that references another table is a foreign
 * key constraint. The ONLY exceptions are the identity/audit columns below —
 * aligned with SmartStack.app, which deliberately leaves these UN-constrained
 * (index only, no FK) because the referenced user may be:
 *   - soft-deleted (audit rows must survive the user's removal), or
 *   - synced from an external identity provider (Entra / Graph), so a hard FK
 *     would break inserts/deletes and external sync.
 *
 * `TenantId` is deliberately NOT here — it MUST be a real FK to `core.tenant_Tenants`
 * (SmartStack.app configures `HasOne<Tenant>().WithMany().HasForeignKey(x => x.TenantId)`).
 *
 * Evidence (SmartStack.app, schema `core`): TicketConfiguration leaves
 * `CreatedByUserId` / `AssignedToUserId` as indexed scalars (no FK);
 * TicketActivityConfiguration leaves `ChangedByUserId`; TicketAssignee leaves the
 * join `UserId`. Contrast: ExternalApplicationUserAccess DOES declare a real FK to
 * User via `OwnerUserId`-style navigation — so generic `*UserId` is NOT blanket-exempt;
 * only the explicit audit-action columns + the bare join `UserId` are.
 *
 * Single source of truth — imported by the entity-audit CLI and the (prose) audit
 * rules DEV-DAT-008 / DM-013 reference this list by name. Override per-run via the
 * audit `--spec` `allowlist` field.
 */
export const FK_AUDIT_ALLOWLIST: readonly RegExp[] = [
  /^CreatedByUserId$/i,
  /^UpdatedByUserId$/i,
  /^ModifiedByUserId$/i,
  /^DeletedByUserId$/i,
  /^ChangedByUserId$/i,
  /^ApprovedByUserId$/i,
  /^AssignedToUserId$/i,
  /^UserId$/i,
]

/** Default allowlist as plain strings (for docs / spec defaults / display). */
export const FK_AUDIT_ALLOWLIST_NAMES: readonly string[] = [
  'CreatedByUserId',
  'UpdatedByUserId',
  'ModifiedByUserId',
  'DeletedByUserId',
  'ChangedByUserId',
  'ApprovedByUserId',
  'AssignedToUserId',
  'UserId',
]

/**
 * True when a column is an intentionally-non-FK identity/audit column.
 * `patterns` lets a caller pass a custom allowlist (e.g. from the audit `--spec`);
 * entries may be RegExp or string (string = exact, case-insensitive match).
 */
export function isAuditAllowlisted(
  column: string,
  patterns: ReadonlyArray<RegExp | string> = FK_AUDIT_ALLOWLIST,
): boolean {
  return patterns.some((p) =>
    typeof p === 'string' ? p.toLowerCase() === column.toLowerCase() : p.test(column),
  )
}
