/**
 * The modules a user account can be granted access to.
 *
 * This list is the authority: the frontend only supplies labels for these
 * names, it never decides what exists or who may enter. Adding a module here
 * makes it grantable everywhere at once — admin cockpit, session payload and
 * the ModuleAccessGuard.
 *
 * Stored as text rather than a Postgres enum on purpose: a new module is then
 * an additive code change instead of a migration that rewrites a type.
 */
export const MODULE_NAMES = [
  'trading',
  'portfolio',
  'market',
  'capital',
  'management',
  'community',
] as const;

export type ModuleName = (typeof MODULE_NAMES)[number];

/**
 * Access levels. WRITE implies READ — a customer with READ on `community`
 * sees channels, posts and chat but cannot publish or write messages.
 */
export const MODULE_ACCESS_LEVELS = ['NONE', 'READ', 'WRITE'] as const;

export type ModuleAccessLevel = (typeof MODULE_ACCESS_LEVELS)[number];

export type ModuleAccessMap = Record<ModuleName, ModuleAccessLevel>;

export function isModuleName(value: unknown): value is ModuleName {
  return typeof value === 'string' && (MODULE_NAMES as readonly string[]).includes(value);
}

/** Every module denied — the starting point for a newly created account. */
export function noModuleAccess(): ModuleAccessMap {
  return Object.fromEntries(MODULE_NAMES.map((name) => [name, 'NONE'])) as ModuleAccessMap;
}

/** Every module writable — what an administrator implicitly holds. */
export function fullModuleAccess(): ModuleAccessMap {
  return Object.fromEntries(MODULE_NAMES.map((name) => [name, 'WRITE'])) as ModuleAccessMap;
}

/** True when `level` satisfies `required`, honouring WRITE ⊃ READ. */
export function satisfies(level: ModuleAccessLevel, required: Exclude<ModuleAccessLevel, 'NONE'>) {
  if (level === 'NONE') return false;
  return required === 'READ' ? true : level === 'WRITE';
}
