// 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.isEmpty;

  /// 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))) {
          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 predicate(ClassEntity classElement)) {
    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 log(String message)) {
    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 log(String message)) {
    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 log(String message)) {
    super.logSummary(log);
    log('Compiled ${_registeredClasses.length} native classes, '
        '${_unusedClasses.length} native classes omitted.');
  }
}
