// Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import '../common/elements.dart' show CommonElements, ElementEnvironment;
import '../elements/entities.dart';
import '../elements/types.dart';
import '../js_backend/native_data.dart' show NativeData;
import '../js_emitter/js_emitter.dart' show CodeEmitterTask;
import '../js_emitter/native_emitter.dart';
import '../options.dart';
import '../universe/use.dart' show TypeUse;
import '../universe/world_impact.dart'
    show WorldImpact, WorldImpactBuilder, WorldImpactBuilderImpl;
import 'behavior.dart';
import 'resolver.dart' show NativeClassFinder;

abstract class NativeEnqueuer {
  final Set<ClassEntity> _registeredClasses = {};
  final Set<ClassEntity> _unusedClasses = {};

  /// Returns whether native classes are being used.
  bool get hasInstantiatedNativeClasses => _registeredClasses.isNotEmpty;

  /// Log message reported if all native types are used.
  String? _allUsedMessage;

  final CompilerOptions _options;
  final ElementEnvironment _elementEnvironment;
  final DartTypes _dartTypes;
  final CommonElements _commonElements;

  /// Subclasses of [NativeEnqueuerBase] are constructed by the backend.
  NativeEnqueuer(
    this._options,
    this._elementEnvironment,
    this._commonElements,
    this._dartTypes,
  );

  bool get enableLiveTypeAnalysis => _options.enableNativeLiveTypeAnalysis;

  /// Called when a [type] has been instantiated natively.
  void onInstantiatedType(InterfaceType type) {
    if (_unusedClasses.remove(type.element)) {
      _registeredClasses.add(type.element);
    }
  }

  /// Initial entry point to native enqueuer.
  WorldImpact processNativeClasses(Iterable<Uri> libraries);

  /// Register [classes] as natively instantiated in [impactBuilder].
  void _registerTypeUses(
    WorldImpactBuilder impactBuilder,
    Set<ClassEntity> classes /*, cause*/,
  ) {
    for (ClassEntity cls in classes) {
      if (!_unusedClasses.contains(cls)) {
        // No need to add [classElement] to [impactBuilder]: it has already been
        // instantiated and we don't track origins of native instantiations
        // precisely.
        continue;
      }
      impactBuilder.registerTypeUse(
        TypeUse.nativeInstantiation(_elementEnvironment.getRawType(cls)),
      );
    }
  }

  /// Registers the [nativeBehavior]. Adds the liveness of its instantiated
  /// types to the world.
  void registerNativeBehavior(
    WorldImpactBuilder impactBuilder,
    NativeBehavior nativeBehavior,
    Object cause,
  ) {
    _processNativeBehavior(impactBuilder, nativeBehavior, cause);
  }

  void _processNativeBehavior(
    WorldImpactBuilder impactBuilder,
    NativeBehavior behavior,
    Object cause,
  ) {
    void registerInstantiation(InterfaceType type) {
      impactBuilder.registerTypeUse(TypeUse.nativeInstantiation(type));
    }

    int unusedBefore = _unusedClasses.length;
    Set<ClassEntity> matchingClasses = {};
    for (var type in behavior.typesInstantiated) {
      if (type is SpecialType) {
        if (type == SpecialType.jsObject) {
          registerInstantiation(_commonElements.objectType);
        }
        continue;
      }
      if (type is InterfaceType) {
        if (type == _commonElements.numType) {
          registerInstantiation(_commonElements.doubleType);
          registerInstantiation(_commonElements.intType);
        } else if (type == _commonElements.intType ||
            type == _commonElements.doubleType ||
            type == _commonElements.stringType ||
            type == _commonElements.nullType ||
            type == _commonElements.boolType ||
            type.element == _commonElements.jsJavaScriptBigIntClass ||
            type.element == _commonElements.jsJavaScriptSymbolClass ||
            type == _commonElements.jsJavaScriptObjectType ||
            _dartTypes.isSubtype(
              type,
              _elementEnvironment.getRawType(_commonElements.jsArrayClass),
            )) {
          registerInstantiation(type);
        } else if (_dartTypes.isSubtype(
          type,
          _elementEnvironment.getRawType(
            _commonElements.jsLegacyJavaScriptObjectClass,
          ),
        )) {
          registerInstantiation(type);
          matchingClasses.add(type.element);
        }
        // TODO(johnniwinther): Improve spec string precision to handle type
        // arguments and implements relations that preserve generics. Currently
        // we cannot distinguish between `List`, `List<dynamic>`, and
        // `List<int>` and take all to mean `List<E>`; in effect not including
        // any native subclasses of generic classes.
        // TODO(johnniwinther,sra): Find and replace uses of `List` with the
        // actual implementation classes such as `JSArray` et al.
        matchingClasses.addAll(
          _findUnusedClassesMatching((ClassEntity nativeClass) {
            InterfaceType nativeType = _elementEnvironment.getRawType(
              nativeClass,
            );
            InterfaceType specType = _elementEnvironment.getRawType(
              type.element,
            );
            return _dartTypes.isSubtype(nativeType, specType);
          }),
        );
      } else if (type is DynamicType) {
        matchingClasses.addAll(_unusedClasses);
      } else {
        assert(type is VoidType, '$type was ${type.runtimeType}');
      }
    }
    if (matchingClasses.isNotEmpty && _registeredClasses.isEmpty) {
      matchingClasses.addAll(_onFirstNativeClass(impactBuilder));
    }
    _registerTypeUses(impactBuilder, matchingClasses /*, cause*/);

    // Give an info so that library developers can compile with -v to find why
    // all the native classes are included.
    if (unusedBefore > 0 && unusedBefore == matchingClasses.length) {
      _allUsedMessage ??= 'All native types marked as used due to $cause.';
    }
  }

  Iterable<ClassEntity> _findUnusedClassesMatching(
    bool Function(ClassEntity classElement) predicate,
  ) {
    return _unusedClasses.where(predicate);
  }

  Iterable<ClassEntity> _onFirstNativeClass(WorldImpactBuilder impactBuilder) {
    return _findNativeExceptions();
  }

  Iterable<ClassEntity> _findNativeExceptions() {
    return _findUnusedClassesMatching((ClassEntity classElement) {
      // TODO(sra): Annotate exception classes in dart:html.
      String name = classElement.name;
      if (name.contains('Exception')) return true;
      if (name.contains('Error')) return true;
      return false;
    });
  }

  /// Emits a summary information using the [log] function.
  void logSummary(void Function(String message) log) {
    if (_allUsedMessage != null) {
      log(_allUsedMessage!);
    }
  }
}

class NativeResolutionEnqueuer extends NativeEnqueuer {
  final NativeClassFinder _nativeClassFinder;

  /// The set of all native classes.  Each native class is in [nativeClasses]
  /// and exactly one of [unusedClasses] and [registeredClasses].
  final Set<ClassEntity> _nativeClasses = {};

  NativeResolutionEnqueuer(
    super.options,
    super.elementEnvironment,
    super.commonElements,
    super.dartTypes,
    this._nativeClassFinder,
  );

  Iterable<ClassEntity> get nativeClassesForTesting => _nativeClasses;

  Iterable<ClassEntity> get registeredClassesForTesting => _registeredClasses;

  Iterable<ClassEntity> get liveNativeClasses => _registeredClasses;

  @override
  WorldImpact processNativeClasses(Iterable<Uri> libraries) {
    WorldImpactBuilderImpl impactBuilder = WorldImpactBuilderImpl();
    Iterable<ClassEntity> nativeClasses = _nativeClassFinder
        .computeNativeClasses(libraries);
    _nativeClasses.addAll(nativeClasses);
    _unusedClasses.addAll(nativeClasses);
    if (!enableLiveTypeAnalysis) {
      _registerTypeUses(impactBuilder, _nativeClasses /*, 'forced'*/);
    }
    return impactBuilder;
  }

  @override
  void logSummary(void Function(String message) log) {
    super.logSummary(log);
    log(
      'Resolved ${_registeredClasses.length} native elements used, '
      '${_unusedClasses.length} native elements dead.',
    );
  }
}

class NativeCodegenEnqueuer extends NativeEnqueuer {
  final CodeEmitterTask _emitter;
  final Set<ClassEntity> _nativeClasses;
  final NativeData _nativeData;

  final Set<ClassEntity> _doneAddSubtypes = {};

  NativeCodegenEnqueuer(
    super.options,
    super.elementEnvironment,
    super.commonElements,
    super.dartTypes,
    this._emitter,
    this._nativeClasses,
    this._nativeData,
  );

  @override
  WorldImpact processNativeClasses(Iterable<Uri> libraries) {
    WorldImpactBuilderImpl impactBuilder = WorldImpactBuilderImpl();
    _unusedClasses.addAll(_nativeClasses);

    if (!enableLiveTypeAnalysis) {
      _registerTypeUses(impactBuilder, _nativeClasses /*, 'forced'*/);
    }

    // TODO: this code is a bit of a hack to add all the resolved classes.
    Set<ClassEntity> matchingClasses = {};
    for (ClassEntity classElement in _nativeClasses) {
      if (_unusedClasses.contains(classElement)) {
        matchingClasses.add(classElement);
      }
    }
    if (matchingClasses.isNotEmpty && _registeredClasses.isEmpty) {
      matchingClasses.addAll(_onFirstNativeClass(impactBuilder));
    }
    _registerTypeUses(impactBuilder, matchingClasses /*, 'was resolved'*/);
    return impactBuilder;
  }

  @override
  void _registerTypeUses(
    WorldImpactBuilder impactBuilder,
    Set<ClassEntity> classes /*, cause*/,
  ) {
    super._registerTypeUses(impactBuilder, classes /*, cause*/);

    for (ClassEntity classElement in classes) {
      // Add the information that this class is a subtype of its supertypes. The
      // code emitter and the ssa builder use that information.
      _addSubtypes(classElement, _emitter.nativeEmitter);
    }
  }

  void _addSubtypes(ClassEntity cls, NativeEmitter emitter) {
    if (!_nativeData.isNativeClass(cls)) return;
    if (_doneAddSubtypes.contains(cls)) return;
    _doneAddSubtypes.add(cls);

    // Walk the superclass chain since classes on the superclass chain might not
    // be instantiated (abstract or simply unused).
    // Note: here and below we expect the superclass always to be non-null
    // because we always start from a native class, which at least has Object as
    // a superclass.
    ClassEntity superclass = _elementEnvironment.getSuperClass(cls)!;
    _addSubtypes(superclass, emitter);

    _elementEnvironment.forEachSupertype(cls, (InterfaceType type) {
      List<ClassEntity> subtypes =
          emitter.subtypes[type.element] ??= <ClassEntity>[];
      subtypes.add(cls);
    });

    // Skip through all the mixin applications in the super class
    // chain. That way, the direct subtypes set only contain the
    // natives classes.
    while (_elementEnvironment.isMixinApplication(superclass)) {
      assert(!_nativeData.isNativeClass(superclass));
      superclass = _elementEnvironment.getSuperClass(superclass)!;
    }

    List<ClassEntity> directSubtypes =
        emitter.directSubtypes[superclass] ??= <ClassEntity>[];
    directSubtypes.add(cls);
  }

  @override
  void logSummary(void Function(String message) log) {
    super.logSummary(log);
    log(
      'Compiled ${_registeredClasses.length} native classes, '
      '${_unusedClasses.length} native classes omitted.',
    );
  }
}
