HHImmutableConfig constructor

HHImmutableConfig({
  1. required String env,
  2. List<HActionHook> actionHooks = const [],
  3. bool usesMeta = true,
  4. List<SerializationHook> serializationHooksParam = const [],
  5. List<TerminalSerializationHook> terminalSerializationHooksParam = const [],
})

Creates or retrieves an immutable configuration. Returns existing instance if one exists for the environment.

Implementation

factory HHImmutableConfig({
  required String env,
  List<HActionHook> actionHooks = const [],
  bool usesMeta = true,
  List<SerializationHook> serializationHooksParam = const [],
  List<TerminalSerializationHook> terminalSerializationHooksParam = const [],
}) {
  // env validation
  if (env.startsWith('_')) {
    throw ArgumentError(
      'Environment name cannot start with an underscore (_).',
    );
  }

  // If usesMeta is false, no action hooks are allowed
  if (!usesMeta && actionHooks.isNotEmpty) {
    throw ArgumentError(
      'Action hooks are not allowed when usesMeta is false.',
    );
  }

  if (_instances.containsKey(env)) {
    final existingInstance = _instances[env]!;

    // Check if settings are identical
    final isIdentical =
        existingInstance.actionHooks.length == actionHooks.length;

    if (!isIdentical) {
      throw ArgumentError(
        'Config with env "$env" already exists with different settings.',
      );
    }

    return existingInstance;
  }

  // Group hooks by event name and pre/post status
  final Map<String, Set<HActionHook>> preHooks = {};
  final Map<String, Set<HActionHook>> postHooks = {};

  for (var hook in actionHooks) {
    for (var latch in hook.latches) {
      final eventName = latch.customEvent ?? latch.triggerType.name;

      if (latch.isPost) {
        postHooks.putIfAbsent(eventName, () => {}).add(hook);
      } else {
        preHooks.putIfAbsent(eventName, () => {}).add(hook);
      }
    }
  }

  // Sort each event's hooks by priority (higher priority first) and convert to lists
  final Map<String, List<HActionHook>> sortedPreHooks = {};
  preHooks.forEach((event, hooksSet) {
    final hooksList = hooksSet.toList();
    hooksList.sort((a, b) {
      final aPriority = a.latches
          .where(
            (l) =>
                (l.customEvent ?? l.triggerType.name) == event && !l.isPost,
          )
          .map((l) => l.priority)
          .fold(0, (max, p) => p > max ? p : max);
      final bPriority = b.latches
          .where(
            (l) =>
                (l.customEvent ?? l.triggerType.name) == event && !l.isPost,
          )
          .map((l) => l.priority)
          .fold(0, (max, p) => p > max ? p : max);
      return bPriority.compareTo(aPriority);
    });
    sortedPreHooks[event] = hooksList;
  });

  final Map<String, List<HActionHook>> sortedPostHooks = {};
  postHooks.forEach((event, hooksSet) {
    final hooksList = hooksSet.toList();
    hooksList.sort((a, b) {
      final aPriority = a.latches
          .where(
            (l) => (l.customEvent ?? l.triggerType.name) == event && l.isPost,
          )
          .map((l) => l.priority)
          .fold(0, (max, p) => p > max ? p : max);
      final bPriority = b.latches
          .where(
            (l) => (l.customEvent ?? l.triggerType.name) == event && l.isPost,
          )
          .map((l) => l.priority)
          .fold(0, (max, p) => p > max ? p : max);
      return bPriority.compareTo(aPriority);
    });
    sortedPostHooks[event] = hooksList;
  });

  // Only store serialization hooks are used (metadata is always Map<String, dynamic>)
  final storeSerializationHooks = serializationHooksParam
      .where((hook) => hook.forStore)
      .toList();

  // Terminal serialization hooks - separate by context
  final metaTerminalSerializationHooks = <TerminalSerializationHook>[];
  final storeTerminalSerializationHooks = <TerminalSerializationHook>[];

  // For now, all terminal hooks go to store (can be enhanced later)
  storeTerminalSerializationHooks.addAll(terminalSerializationHooksParam);

  final newInstance = HHImmutableConfig._internal(
    sortedPreHooks,
    sortedPostHooks,
    storeSerializationHooks,
    metaTerminalSerializationHooks,
    storeTerminalSerializationHooks,
    env: env,
    usesMeta: usesMeta,
    actionHooks: actionHooks,
    serializationHooks: serializationHooksParam,
    terminalSerializationHooks: terminalSerializationHooksParam,
  );

  _instances[env] = newInstance;
  return newInstance;
}