content: import 'package:d4rt/d4rt.dart';
  import 'package:d4rt/src/module_loader.dart';
  
  /// Represents an enum type defined in the host Dart environment and bridged into the interpreter.
  /// It holds the definition and provides access to its values.
  class BridgedEnum implements RuntimeType {
    /// The name of the enum.
    @override
    final String name;
  
    /// A map of the enum's value names to their corresponding BridgedEnumValue instances.
    final Map<String, BridgedEnumValue> values;
  
    /// Instance getter adapters (shared by all values).
    Map<String, BridgedInstanceGetterAdapter> getters = {};
  
    /// Instance method adapters (shared by all values).
    Map<String, BridgedMethodAdapter> methods = {};
  
    /// Creates a definition for a bridged enum.
    BridgedEnum(this.name, this.values);
  
    @override
    String toString() => 'BridgedEnum($name)';
  
    @override
    bool isSubtypeOf(RuntimeType other, {Object? value}) {
      return other.name == 'Object' || other == this;
    }
  
    /// Retrieves an enum value by its name.
    BridgedEnumValue? getValue(String valueName) {
      return values[valueName];
    }
  
    /// Returns the list of all values for this enum.
    List<BridgedEnumValue> get enumValues => values.values.toList();
  }
  
  /// Represents a specific value of a [BridgedEnum].
  /// It holds the value's name, index, and the original native enum value.
  class BridgedEnumValue implements RuntimeValue {
    /// The [BridgedEnum] definition this value belongs to.
    final BridgedEnum enumType;
  
    /// The name of the enum value (e.g., 'red' for Color.red).
    final String name;
  
    /// The index of the enum value in its definition order.
    final int index;
  
    /// The original native Dart enum value.
    final Object nativeValue;
  
    /// Instance getter adapters (potentially specific to this value if needed in the future,
    /// but currently shared via BridgedEnum).
    final Map<String, BridgedInstanceGetterAdapter> _getters;
  
    /// Instance method adapters.
    final Map<String, BridgedMethodAdapter> _methods;
  
    BridgedEnumValue(this.enumType, this.name, this.index, this.nativeValue,
        {Map<String, BridgedInstanceGetterAdapter>?
            getters, // Rendre optionnels ici
        Map<String, BridgedMethodAdapter>? methods})
        : _getters = getters ?? {},
          _methods = methods ?? {};
  
    // Implement the required getter from RuntimeValue
    @override
    RuntimeType get valueType => enumType;
  
    @override
    Object? get(String identifier) {
      // Access standard enum properties
      switch (identifier) {
        case 'index':
          return index;
        case 'name':
          return name;
        // 'toString' is handled below via adapters or the invoke method
        default:
          // 1. Check for custom instance getters
          final getterAdapter =
              _getters[identifier] ?? enumType.getters[identifier];
          if (getterAdapter != null) {
            try {
              // Note: The visitor is null here because get() has no visitor context.
              // If the adapter needs the visitor, the interface will need to be revised.
              return getterAdapter(null, nativeValue);
            } catch (e) {
              throw RuntimeError(
                  'Error executing bridged getter "$identifier" on ${enumType.name}.$name: $e');
            }
          }
  
          // 2. Check for instance methods (for cases like .toString() called as a getter)
          // Or to return a callable function representing the method.
          final methodAdapter =
              _methods[identifier] ?? enumType.methods[identifier];
          if (methodAdapter != null) {
            // Return a function that wraps the bridged method call
            // (or handle directly if it's a getter disguised as a method, like toString)
            if (identifier == 'toString') {
              // Special case for toString() via get
              // We could call the toString adapter if it exists, otherwise fallback
              try {
                // Try to call the toString adapter (which should not need args)
                return methodAdapter(
                    InterpreterVisitor(
                        globalEnvironment: Environment(),
                        moduleLoader: ModuleLoader(Environment(), {}, [], [])),
                    nativeValue,
                    [],
                    {});
              } catch (_) {
                // Fallback if the adapter does not exist or fails
                return '${enumType.name}.$name';
              }
            }
            // For other methods, we could return a callable function here if needed.
            // For now, throw an error if trying to access a method via get.
            throw RuntimeError(
                'Cannot access method "$identifier" as a property on enum value ${enumType.name}.$name. Use call syntax ().');
          }
  
          // 3. If it's neither a standard property, nor a custom getter/method
          throw RuntimeError(
              'Property "$identifier" not found on enum value ${enumType.name}.$name');
      }
    }
  
    @override
    void set(String identifier, Object? value) {
      // Enum values are typically immutable
      throw RuntimeError(
          'Cannot set property "$identifier" on enum value ${enumType.name}.$name');
    }
  
    Object? invoke(InterpreterVisitor visitor, String method, List<Object?> args,
        Map<String, Object?> namedArgs) {
      final methodAdapter = _methods[method] ?? enumType.methods[method];
      if (methodAdapter == null) {
        // Special case: if calling .toString() and there is no specific adapter,
        // return the standard representation.
        if (method == 'toString' && args.isEmpty && namedArgs.isEmpty) {
          return '${enumType.name}.$name';
        }
        throw RuntimeError(
            'Method "$method" not found on enum value ${enumType.name}.$name');
      }
  
      try {
        // Call the bridged method adapter
        return methodAdapter(
          visitor, // Pass the visitor
          nativeValue, // The native enum object is the target
          args, // Interpreted positional arguments
          namedArgs, // Interpreted named arguments (if supported by the adapter)
        );
      } catch (e) {
        throw RuntimeError(
            'Error executing bridged method "$method" on ${enumType.name}.$name: $e');
      }
    }
  
    @override
    String toString() {
      // Try to call the toString() adapter if it exists
      final toStringAdapter =
          _methods['toString'] ?? enumType.methods['toString'];
      if (toStringAdapter != null) {
        try {
          // Call without specific visitor or argument here, as it's just for representation
          return toStringAdapter(
              InterpreterVisitor(
                  globalEnvironment: Environment(),
                  moduleLoader: ModuleLoader(Environment(), {}, [], [])),
              nativeValue,
              [],
              {}).toString();
        } catch (_) {
          // Fallback if the adapter fails
          return '${enumType.name}.$name (native toString failed)';
        }
      }
      // Provide a default representation if no toString adapter is provided
      return '${enumType.name}.$name';
    }
  
    // Consider adding equality checks based on nativeValue or index/type if needed
    @override
    bool operator ==(Object other) =>
        identical(this, other) ||
        other is BridgedEnumValue &&
            runtimeType == other.runtimeType &&
            // Compare bridged enum types by name to avoid instance issues
            enumType.name == other.enumType.name &&
            index == other.index &&
            nativeValue == other.nativeValue; // Compare native values too
  
    @override
    int get hashCode =>
        enumType.name.hashCode ^ index.hashCode ^ nativeValue.hashCode;
  }
  