// Copyright 2014 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// @dart = 2.8

import 'package:meta/meta.dart';
import 'package:mime/mime.dart' as mime;
import 'package:process/process.dart';

import '../../artifacts.dart';
import '../../base/common.dart';
import '../../base/file_system.dart';
import '../../base/io.dart';
import '../../base/logger.dart';
import '../../build_info.dart';
import '../../convert.dart';
import '../../devfs.dart';
import '../build_system.dart';

List<Map<String, dynamic>> _getList(dynamic object, String errorMessage) {
  if (object is List<dynamic>) {
    return object.cast<Map<String, dynamic>>();
  }
  throw IconTreeShakerException._(errorMessage);
}

/// A class that wraps the functionality of the const finder package and the
/// font subset utility to tree shake unused icons from fonts.
class IconTreeShaker {
  /// Creates a wrapper for icon font subsetting.
  ///
  /// The environment parameter must not be null.
  ///
  /// If the `fontManifest` parameter is null, [enabled] will return false since
  /// there are no fonts to shake.
  ///
  /// The constructor will validate the environment and print a warning if
  /// font subsetting has been requested in a debug build mode.
  IconTreeShaker(
    this._environment,
    DevFSStringContent fontManifest, {
    @required ProcessManager processManager,
    @required Logger logger,
    @required FileSystem fileSystem,
    @required Artifacts artifacts,
  }) : assert(_environment != null),
       assert(processManager != null),
       assert(logger != null),
       assert(fileSystem != null),
       assert(artifacts != null),
       _processManager = processManager,
       _logger = logger,
       _fs = fileSystem,
       _artifacts = artifacts,
       _fontManifest = fontManifest?.string {
    if (_environment.defines[kIconTreeShakerFlag] == 'true' &&
        _environment.defines[kBuildMode] == 'debug') {
      logger.printError('Font subsetting is not supported in debug mode. The '
                         '--tree-shake-icons flag will be ignored.');
    }
  }

  /// The MIME types for supported font sets.
  static const Set<String> kTtfMimeTypes = <String>{
    'font/ttf', // based on internet search
    'font/opentype',
    'font/otf',
    'application/x-font-opentype',
    'application/x-font-otf',
    'application/x-font-ttf', // based on running locally.
  };

  /// The [Source] inputs that targets using this should depend on.
  ///
  /// See [Target.inputs].
  static const List<Source> inputs = <Source>[
    Source.pattern('{FLUTTER_ROOT}/packages/flutter_tools/lib/src/build_system/targets/icon_tree_shaker.dart'),
    Source.artifact(Artifact.constFinder),
    Source.artifact(Artifact.fontSubset),
  ];

  final Environment _environment;
  final String _fontManifest;
  Future<void> _iconDataProcessing;
  Map<String, _IconTreeShakerData> _iconData;

  final ProcessManager _processManager;
  final Logger _logger;
  final FileSystem _fs;
  final Artifacts _artifacts;

  /// Whether font subsetting should be used for this [Environment].
  bool get enabled => _fontManifest != null
                   && _environment.defines[kIconTreeShakerFlag] == 'true'
                   && _environment.defines[kBuildMode] != 'debug';

  // Fills the [_iconData] map.
  Future<void> _getIconData(Environment environment) async {
    if (!enabled) {
      return;
    }

    final File appDill = environment.buildDir.childFile('app.dill');
    if (!appDill.existsSync()) {
      throw IconTreeShakerException._('Expected to find kernel file at ${appDill.path}, but no file found.');
    }
    final File constFinder = _fs.file(
      _artifacts.getArtifactPath(Artifact.constFinder),
    );
    final File dart = _fs.file(
      _artifacts.getHostArtifact(HostArtifact.engineDartBinary),
    );

    final Map<String, List<int>> iconData = await _findConstants(
      dart,
      constFinder,
      appDill,
    );
    final Set<String> familyKeys = iconData.keys.toSet();

    final Map<String, String> fonts = await _parseFontJson(
      _fontManifest,
      familyKeys,
    );

    if (fonts.length != iconData.length) {
      environment.logger.printStatus(
        'Expected to find fonts for ${iconData.keys}, but found '
        '${fonts.keys}. This usually means you are referring to '
        'font families in an IconData class but not including them '
        'in the assets section of your pubspec.yaml, are missing '
        'the package that would include them, or are missing '
        '"uses-material-design: true".',
      );
    }

    final Map<String, _IconTreeShakerData> result = <String, _IconTreeShakerData>{};
    for (final MapEntry<String, String> entry in fonts.entries) {
      result[entry.value] = _IconTreeShakerData(
        family: entry.key,
        relativePath: entry.value,
        codePoints: iconData[entry.key],
      );
    }
    _iconData = result;
  }

  /// Calls font-subset, which transforms the [input] font file to a
  /// subsetted version at [outputPath].
  ///
  /// All parameters are required.
  ///
  /// If [enabled] is false, or the relative path is not recognized as an icon
  /// font used in the Flutter application, this returns false.
  /// If the font-subset subprocess fails, it will [throwToolExit].
  /// Otherwise, it will return true.
  Future<bool> subsetFont({
    @required File input,
    @required String outputPath,
    @required String relativePath,
  }) async {
    if (!enabled) {
      return false;
    }
    if (input.lengthSync() < 12) {
      return false;
    }
    final String mimeType = mime.lookupMimeType(
      input.path,
      headerBytes: await input.openRead(0, 12).first,
    );
    if (!kTtfMimeTypes.contains(mimeType)) {
      return false;
    }
    await (_iconDataProcessing ??= _getIconData(_environment));
    assert(_iconData != null);

    final _IconTreeShakerData iconTreeShakerData = _iconData[relativePath];
    if (iconTreeShakerData == null) {
      return false;
    }

    final File fontSubset = _fs.file(
      _artifacts.getArtifactPath(Artifact.fontSubset),
    );
    if (!fontSubset.existsSync()) {
      throw IconTreeShakerException._('The font-subset utility is missing. Run "flutter doctor".');
    }

    final List<String> cmd = <String>[
      fontSubset.path,
      outputPath,
      input.path,
    ];
    final String codePoints = iconTreeShakerData.codePoints.join(' ');
    _logger.printTrace('Running font-subset: ${cmd.join(' ')}, '
                       'using codepoints $codePoints');
    final Process fontSubsetProcess = await _processManager.start(cmd);
    try {
      fontSubsetProcess.stdin.writeln(codePoints);
      await fontSubsetProcess.stdin.flush();
      await fontSubsetProcess.stdin.close();
    } on Exception {
      // handled by checking the exit code.
    }

    final int code = await fontSubsetProcess.exitCode;
    if (code != 0) {
      _logger.printTrace(await utf8.decodeStream(fontSubsetProcess.stdout));
      _logger.printError(await utf8.decodeStream(fontSubsetProcess.stderr));
      throw IconTreeShakerException._('Font subsetting failed with exit code $code.');
    }
    return true;
  }

  /// Returns a map of { fontFamily: relativePath } pairs.
  Future<Map<String, String>> _parseFontJson(
    String fontManifestData,
    Set<String> families,
  ) async {
    final Map<String, String> result = <String, String>{};
    final List<Map<String, dynamic>> fontList = _getList(
      json.decode(fontManifestData),
      'FontManifest.json invalid: expected top level to be a list of objects.',
    );

    for (final Map<String, dynamic> map in fontList) {
      if (map['family'] is! String) {
        throw IconTreeShakerException._(
          'FontManifest.json invalid: expected the family value to be a string, '
          'got: ${map['family']}.');
      }
      final String familyKey = map['family'] as String;
      if (!families.contains(familyKey)) {
        continue;
      }
      final List<Map<String, dynamic>> fonts = _getList(
        map['fonts'],
        'FontManifest.json invalid: expected "fonts" to be a list of objects.',
      );
      if (fonts.length != 1) {
        throw IconTreeShakerException._(
          'This tool cannot process icon fonts with multiple fonts in a '
          'single family.');
      }
      if (fonts.first['asset'] is! String) {
        throw IconTreeShakerException._(
          'FontManifest.json invalid: expected "asset" value to be a string, '
          'got: ${map['assets']}.');
      }
      result[familyKey] = fonts.first['asset'] as String;
    }
    return result;
  }

  Future<Map<String, List<int>>> _findConstants(
    File dart,
    File constFinder,
    File appDill,
  ) async {
    final List<String> cmd = <String>[
      dart.path,
      '--disable-dart-dev',
      constFinder.path,
      '--kernel-file', appDill.path,
      '--class-library-uri', 'package:flutter/src/widgets/icon_data.dart',
      '--class-name', 'IconData',
    ];
    _logger.printTrace('Running command: ${cmd.join(' ')}');
    final ProcessResult constFinderProcessResult = await _processManager.run(cmd);

    if (constFinderProcessResult.exitCode != 0) {
      throw IconTreeShakerException._('ConstFinder failure: ${constFinderProcessResult.stderr}');
    }
    final dynamic jsonDecode = json.decode(constFinderProcessResult.stdout as String);
    if (jsonDecode is! Map<String, dynamic>) {
      throw IconTreeShakerException._(
        'Invalid ConstFinder output: expected a top level JSON object, '
        'got $jsonDecode.');
    }
    final Map<String, dynamic> constFinderMap = jsonDecode as Map<String, dynamic>;
    final _ConstFinderResult constFinderResult = _ConstFinderResult(constFinderMap);
    if (constFinderResult.hasNonConstantLocations) {
      _logger.printError('This application cannot tree shake icons fonts. '
                         'It has non-constant instances of IconData at the '
                         'following locations:', emphasis: true);
      for (final Map<String, dynamic> location in constFinderResult.nonConstantLocations) {
        _logger.printError(
          '- ${location['file']}:${location['line']}:${location['column']}',
          indent: 2,
          hangingIndent: 4,
        );
      }
      throwToolExit('Avoid non-constant invocations of IconData or try to '
                    'build again with --no-tree-shake-icons.');
    }
    return _parseConstFinderResult(constFinderResult);
  }

  Map<String, List<int>> _parseConstFinderResult(_ConstFinderResult constants) {
    final Map<String, List<int>> result = <String, List<int>>{};
    for (final Map<String, dynamic> iconDataMap in constants.constantInstances) {
      if ((iconDataMap['fontPackage'] ?? '') is! String || // Null is ok here.
           iconDataMap['fontFamily'] is! String ||
           iconDataMap['codePoint'] is! num) {
        throw IconTreeShakerException._(
          'Invalid ConstFinder result. Expected "fontPackage" to be a String, '
          '"fontFamily" to be a String, and "codePoint" to be an int, '
          'got: $iconDataMap.');
      }
      final String package = iconDataMap['fontPackage'] as String;
      final String family = iconDataMap['fontFamily'] as String;
      final String key = package == null
        ? family
        : 'packages/$package/$family';
      result[key] ??= <int>[];
      result[key].add((iconDataMap['codePoint'] as num).round());
    }
    return result;
  }
}

class _ConstFinderResult {
  _ConstFinderResult(this.result);

  final Map<String, dynamic> result;

  List<Map<String, dynamic>> _constantInstances;
  List<Map<String, dynamic>> get constantInstances {
    _constantInstances ??= _getList(
      result['constantInstances'],
      'Invalid ConstFinder output: Expected "constInstances" to be a list of objects.',
    );
    return _constantInstances;
  }

  List<Map<String, dynamic>> _nonConstantLocations;
  List<Map<String, dynamic>> get nonConstantLocations {
    _nonConstantLocations ??= _getList(
      result['nonConstantLocations'],
      'Invalid ConstFinder output: Expected "nonConstLocations" to be a list of objects',
    );
    return _nonConstantLocations;
  }

  bool get hasNonConstantLocations => nonConstantLocations.isNotEmpty;
}

/// The font family name, relative path to font file, and list of code points
/// the application is using.
class _IconTreeShakerData {
  /// All parameters are required.
  const _IconTreeShakerData({
    @required this.family,
    @required this.relativePath,
    @required this.codePoints,
  }) : assert(family != null),
       assert(relativePath != null),
       assert(codePoints != null);

  /// The font family name, e.g. "MaterialIcons".
  final String family;

  /// The relative path to the font file.
  final String relativePath;

  /// The list of code points for the font.
  final List<int> codePoints;

  @override
  String toString() => 'FontSubsetData($family, $relativePath, $codePoints)';
}

class IconTreeShakerException implements Exception {
  IconTreeShakerException._(this.message);

  final String message;

  @override
  String toString() => 'IconTreeShakerException: $message\n\n'
    'To disable icon tree shaking, pass --no-tree-shake-icons to the requested '
    'flutter build command';
}
