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

import 'dart:async';

import 'package:package_config/package_config.dart';
import 'package:process/process.dart';
import 'package:vm_service/vm_service.dart' as vm_service;

import 'artifacts.dart';
import 'asset.dart';
import 'base/config.dart';
import 'base/context.dart';
import 'base/file_system.dart';
import 'base/io.dart';
import 'base/logger.dart';
import 'base/net.dart';
import 'base/os.dart';
import 'build_info.dart';
import 'build_system/tools/asset_transformer.dart';
import 'build_system/tools/shader_compiler.dart';
import 'compile.dart';
import 'convert.dart' show base64, utf8;
import 'vmservice.dart';

class DevFSConfig {
  /// Should DevFS assume that symlink targets are stable?
  bool cacheSymlinks = false;

  /// Should DevFS assume that there are no symlinks to directories?
  bool noDirectorySymlinks = false;
}

DevFSConfig? get devFSConfig => context.get<DevFSConfig>();

/// Common superclass for content copied to the device.
abstract class DevFSContent {
  /// Return true if the entry has been modified since it was last marked clean.
  bool get isModified;

  /// Mark the content as clean, resetting the [isModified] state.
  void markClean();

  /// Return true if the entry has been modified after the given time.
  bool isModifiedAfter(DateTime time);

  int get size;

  Future<List<int>> contentsAsBytes();

  Stream<List<int>> contentsAsStream();

  Stream<List<int>> contentsAsCompressedStream(OperatingSystemUtils osUtils) {
    return osUtils.gzipLevel1Stream(contentsAsStream());
  }
}

// File content to be copied to the device.
class DevFSFileContent extends DevFSContent {
  DevFSFileContent(this.file);

  final FileSystemEntity file;
  File? _linkTarget;
  FileStat? _fileStat;

  File _getFile() {
    final File? linkTarget = _linkTarget;
    if (linkTarget != null) {
      return linkTarget;
    }
    if (file is Link) {
      // The link target.
      return file.fileSystem.file(file.resolveSymbolicLinksSync());
    }
    return file as File;
  }

  (FileStat?, File?) _statFile() {
    File? linkTarget = _linkTarget;
    if (linkTarget != null) {
      // Stat the cached symlink target.
      final FileStat fileStat = linkTarget.statSync();
      if (fileStat.type != FileSystemEntityType.notFound) {
        return (fileStat, linkTarget);
      }
      linkTarget = null;
    }
    final FileStat fileStat = file.statSync();
    if (fileStat.type == FileSystemEntityType.notFound) {
      return (null, null);
    }
    if (fileStat.type == FileSystemEntityType.link) {
      try {
        final String resolved = file.resolveSymbolicLinksSync();
        final File resolvedFile = file.fileSystem.file(resolved);
        // Stat the link target.
        final FileStat fileStat = resolvedFile.statSync();
        if (fileStat.type == FileSystemEntityType.notFound) {
          return (null, null);
        }
        return (fileStat, resolvedFile);
      } on FileSystemException {
        return (null, null);
      }
    }
    return (fileStat, null);
  }

  @override
  bool get isModified {
    final (FileStat? currentStat, _) = _statFile();
    if (_fileStat == null && currentStat == null) {
      return false;
    }
    return _fileStat == null ||
        currentStat == null ||
        currentStat.modified.isAfter(_fileStat!.modified);
  }

  @override
  void markClean() {
    final (FileStat? fileStat, File? linkTarget) = _statFile();
    _fileStat = fileStat;
    if (linkTarget != null && (devFSConfig?.cacheSymlinks ?? false)) {
      _linkTarget = linkTarget;
    } else {
      _linkTarget = null;
    }
  }

  @override
  bool isModifiedAfter(DateTime time) {
    // Whether the file changed after [time] only depends on the file's current
    // modification time, not on the cached [_fileStat]. Falling back to the
    // cached stat (e.g. `_fileStat == null`) would report a freshly created
    // DevFSFileContent as modified even when its file is older than [time].
    final (FileStat? currentStat, _) = _statFile();
    return currentStat != null && currentStat.modified.isAfter(time);
  }

  @override
  int get size {
    final FileStat? stat = _fileStat ?? _statFile().$1;
    return stat?.size ?? 0;
  }

  @override
  Future<List<int>> contentsAsBytes() async => _getFile().readAsBytes();

  @override
  Stream<List<int>> contentsAsStream() => _getFile().openRead();
}

/// Byte content to be copied to the device.
class DevFSByteContent extends DevFSContent {
  DevFSByteContent(this._bytes);

  final List<int> _bytes;
  final _creationTime = DateTime.now();
  var _isModified = true;

  List<int> get bytes => _bytes;

  @override
  bool get isModified => _isModified;

  @override
  void markClean() {
    _isModified = false;
  }

  @override
  bool isModifiedAfter(DateTime time) {
    return _creationTime.isAfter(time);
  }

  @override
  int get size => _bytes.length;

  @override
  Future<List<int>> contentsAsBytes() async => _bytes;

  @override
  Stream<List<int>> contentsAsStream() => Stream<List<int>>.fromIterable(<List<int>>[_bytes]);
}

/// String content to be copied to the device.
class DevFSStringContent extends DevFSByteContent {
  DevFSStringContent(String string) : _string = string, super(utf8.encode(string));

  final String _string;

  String get string => _string;
}

/// A string compressing DevFSContent.
///
/// A specialized DevFSContent similar to DevFSByteContent where the contents
/// are the compressed bytes of a string. Its difference is that the original
/// uncompressed string can be compared with directly without the indirection
/// of a compute-expensive uncompress/decode and compress/encode to compare
/// the strings.
///
/// The `hintString` parameter is a zlib dictionary hinting mechanism to suggest
/// the most common string occurrences to potentially assist with compression.
class DevFSStringCompressingBytesContent extends DevFSContent {
  DevFSStringCompressingBytesContent(this._string, {String? hintString})
    : _compressor = ZLibEncoder(
        dictionary: hintString == null ? null : utf8.encode(hintString),
        gzip: true,
        level: 9,
      );

  final String _string;
  final ZLibEncoder _compressor;
  final _creationTime = DateTime.now();

  var _isModified = true;

  late final List<int> bytes = _compressor.convert(utf8.encode(_string));

  @override
  bool get isModified => _isModified;

  @override
  void markClean() {
    _isModified = false;
  }

  @override
  bool isModifiedAfter(DateTime time) {
    return _creationTime.isAfter(time);
  }

  @override
  int get size => bytes.length;

  @override
  Future<List<int>> contentsAsBytes() async => bytes;

  @override
  Stream<List<int>> contentsAsStream() => Stream<List<int>>.value(bytes);

  /// This checks the source string with another string.
  bool equals(String string) => _string == string;
}

class DevFSException implements Exception {
  DevFSException(this.message, [this.error, this.stackTrace]);
  final String message;
  final dynamic error;
  final StackTrace? stackTrace;

  @override
  String toString() => 'DevFSException($message, $error, $stackTrace)';
}

/// Interface responsible for syncing asset files to a development device.
abstract class DevFSWriter {
  /// Write the assets in [entries] to the target device.
  ///
  /// The keys of the map are relative from the [baseUri].
  ///
  /// Throws a [DevFSException] if the process fails to complete.
  Future<void> write(Map<Uri, DevFSContent> entries, Uri baseUri, DevFSWriter parent);
}

class _DevFSHttpWriter implements DevFSWriter {
  _DevFSHttpWriter(
    this.fsName,
    FlutterVmService serviceProtocol, {
    required OperatingSystemUtils osUtils,
    required HttpClient httpClient,
    required Logger logger,
    Duration? uploadRetryThrottle,
  }) : httpAddress = serviceProtocol.httpAddress,
       _client = httpClient,
       _osUtils = osUtils,
       _uploadRetryThrottle = uploadRetryThrottle,
       _logger = logger;

  final HttpClient _client;
  final OperatingSystemUtils _osUtils;
  final Logger _logger;
  final Duration? _uploadRetryThrottle;

  final String fsName;
  final Uri? httpAddress;

  // 3 was chosen to try to limit the variance in the time it takes to execute
  // `await request.close()` since there is a known bug in Dart where it doesn't
  // always return a status code in response to a PUT request:
  // https://github.com/dart-lang/sdk/issues/43525.
  static const kMaxInFlight = 3;

  var _inFlight = 0;
  late Map<Uri, DevFSContent> _outstanding;
  late Completer<void> _completer;

  @override
  Future<void> write(Map<Uri, DevFSContent> entries, Uri devFSBase, [DevFSWriter? parent]) async {
    try {
      _client.maxConnectionsPerHost = kMaxInFlight;
      _completer = Completer<void>();
      _outstanding = Map<Uri, DevFSContent>.of(entries);
      _scheduleWrites();
      await _completer.future;
    } on SocketException catch (socketException, stackTrace) {
      _logger.printTrace('DevFS sync failed. Lost connection to device: $socketException');
      throw DevFSException('Lost connection to device.', socketException, stackTrace);
    } on Exception catch (exception, stackTrace) {
      _logger.printError('Could not update files on device: $exception');
      throw DevFSException('Sync failed', exception, stackTrace);
    }
  }

  void _scheduleWrites() {
    while ((_inFlight < kMaxInFlight) && (!_completer.isCompleted) && _outstanding.isNotEmpty) {
      final Uri deviceUri = _outstanding.keys.first;
      final DevFSContent content = _outstanding.remove(deviceUri)!;
      _startWrite(deviceUri, content, retry: 10);
      _inFlight += 1;
    }
    if ((_inFlight == 0) && (!_completer.isCompleted) && _outstanding.isEmpty) {
      _completer.complete();
    }
  }

  Future<void> _startWrite(Uri deviceUri, DevFSContent content, {int retry = 0}) async {
    while (true) {
      try {
        final HttpClientRequest request = await _client.putUrl(httpAddress!);
        request.headers.removeAll(HttpHeaders.acceptEncodingHeader);
        request.headers.add('dev_fs_name', fsName);
        request.headers.add('dev_fs_uri_b64', base64.encode(utf8.encode('$deviceUri')));
        final Stream<List<int>> contents = content.contentsAsCompressedStream(_osUtils);
        await request.addStream(contents);
        // Once the bug in Dart is solved we can remove the timeout
        // (https://github.com/dart-lang/sdk/issues/43525).
        try {
          final HttpClientResponse response = await request.close().timeout(
            const Duration(seconds: 60),
          );
          response.listen(
            (_) {},
            onError: (dynamic error) {
              _logger.printTrace('error: $error');
            },
            cancelOnError: true,
          );
        } on TimeoutException {
          request.abort();
          // This should throw "HttpException: Request has been aborted".
          await request.done;
          // Just to be safe we rethrow the TimeoutException.
          rethrow;
        }
        break;
      } on Exception catch (error, trace) {
        if (!_completer.isCompleted) {
          _logger.printTrace('Error writing "$deviceUri" to DevFS: $error');
          if (retry > 0) {
            retry--;
            _logger.printTrace('trying again in a few - $retry more attempts left');
            await Future<void>.delayed(_uploadRetryThrottle ?? const Duration(milliseconds: 500));
            continue;
          }
          _completer.completeError(error, trace);
        }
      }
    }
    _inFlight -= 1;
    _scheduleWrites();
  }
}

// Basic statistics for DevFS update operation.
class UpdateFSReport {
  UpdateFSReport({
    bool success = false,
    int invalidatedSourcesCount = 0,
    int syncedBytes = 0,
    int scannedSourcesCount = 0,
    Duration compileDuration = Duration.zero,
    Duration transferDuration = Duration.zero,
    Duration findInvalidatedDuration = Duration.zero,
    bool hotReloadRejected = false,
  }) : _success = success,
       _invalidatedSourcesCount = invalidatedSourcesCount,
       _syncedBytes = syncedBytes,
       _scannedSourcesCount = scannedSourcesCount,
       _compileDuration = compileDuration,
       _transferDuration = transferDuration,
       _findInvalidatedDuration = findInvalidatedDuration,
       _hotReloadRejected = hotReloadRejected;

  bool get success => _success;
  int get invalidatedSourcesCount => _invalidatedSourcesCount;
  int get syncedBytes => _syncedBytes;
  int get scannedSourcesCount => _scannedSourcesCount;
  Duration get compileDuration => _compileDuration;
  Duration get transferDuration => _transferDuration;
  Duration get findInvalidatedDuration => _findInvalidatedDuration;

  /// Whether there was a hot reload rejection in this compile.
  ///
  /// On the web, hot reload can be rejected during compile time instead of at
  /// runtime.
  bool get hotReloadRejected => _hotReloadRejected;

  bool _success;
  int _invalidatedSourcesCount;
  int _syncedBytes;
  int _scannedSourcesCount;
  Duration _compileDuration;
  Duration _transferDuration;
  Duration _findInvalidatedDuration;
  bool _hotReloadRejected;

  void incorporateResults(UpdateFSReport report) {
    if (!report._success) {
      _success = false;
    }
    _invalidatedSourcesCount += report._invalidatedSourcesCount;
    _syncedBytes += report._syncedBytes;
    _scannedSourcesCount += report._scannedSourcesCount;
    _compileDuration += report._compileDuration;
    _transferDuration += report._transferDuration;
    _findInvalidatedDuration += report._findInvalidatedDuration;
    if (report._hotReloadRejected) {
      _hotReloadRejected = true;
    }
  }
}

class DevFS {
  /// Create a [DevFS] named [fsName] for the local files in [rootDirectory].
  ///
  /// Failed uploads are retried after [uploadRetryThrottle] duration, defaults to 500ms.
  DevFS(
    FlutterVmService serviceProtocol,
    this.fsName,
    this.rootDirectory, {
    required OperatingSystemUtils osUtils,
    required Logger logger,
    required FileSystem fileSystem,
    required ProcessManager processManager,
    required Artifacts artifacts,
    required BuildMode buildMode,
    HttpClient? httpClient,
    Duration? uploadRetryThrottle,
    StopwatchFactory stopwatchFactory = const StopwatchFactory(),
    Config? config,
  }) : _vmService = serviceProtocol,
       _logger = logger,
       _fileSystem = fileSystem,
       _httpWriter = _DevFSHttpWriter(
         fsName,
         serviceProtocol,
         osUtils: osUtils,
         logger: logger,
         uploadRetryThrottle: uploadRetryThrottle,
         httpClient:
             httpClient ??
             ((context.get<HttpClientFactory>() == null)
                 ? HttpClient()
                 : context.get<HttpClientFactory>()!()),
       ),
       _stopwatchFactory = stopwatchFactory,
       _config = config,
       _assetTransformer = DevelopmentAssetTransformer(
         transformer: AssetTransformer(
           processManager: processManager,
           fileSystem: fileSystem,
           dartBinaryPath: artifacts.getArtifactPath(Artifact.engineDartBinary),
           buildMode: buildMode,
         ),
         fileSystem: fileSystem,
         logger: logger,
       );

  final FlutterVmService _vmService;
  final _DevFSHttpWriter _httpWriter;
  final Logger _logger;
  final FileSystem _fileSystem;
  final StopwatchFactory _stopwatchFactory;
  final Config? _config;
  final DevelopmentAssetTransformer _assetTransformer;

  final String fsName;
  final Directory rootDirectory;
  final assetPathsToEvict = <String>{};
  final shaderPathsToEvict = <String>{};

  // A flag to indicate whether we have called `setAssetDirectory` on the target device.
  bool hasSetAssetDirectory = false;

  /// Whether the font manifest was uploaded during [update].
  bool didUpdateFontManifest = false;

  List<Uri> sources = <Uri>[];
  DateTime? lastCompiled;
  DateTime? _previousCompiled;
  PackageConfig? lastPackageConfig;

  Uri? _baseUri;
  Uri? get baseUri => _baseUri;

  Uri deviceUriToHostUri(Uri deviceUri) {
    final deviceUriString = deviceUri.toString();
    final baseUriString = baseUri.toString();
    if (deviceUriString.startsWith(baseUriString)) {
      final String deviceUriSuffix = deviceUriString.substring(baseUriString.length);
      return rootDirectory.uri.resolve(deviceUriSuffix);
    }
    return deviceUri;
  }

  Future<Uri> create() async {
    _logger.printTrace('DevFS: Creating new filesystem on the device ($_baseUri)');
    try {
      final vm_service.Response response = await _vmService.createDevFS(fsName);
      _baseUri = Uri.parse(response.json!['uri'] as String);
    } on vm_service.RPCError catch (rpcException) {
      if (rpcException.code == vm_service.RPCErrorKind.kServiceDisappeared.code ||
          rpcException.code == vm_service.RPCErrorKind.kConnectionDisposed.code ||
          rpcException.message.contains('Service connection disposed')) {
        // This can happen if the device has been disconnected, so translate to
        // a DevFSException, which the caller will handle.
        throw DevFSException('Service disconnected', rpcException);
      }
      // 1001 is kFileSystemAlreadyExists in //dart/runtime/vm/json_stream.h
      if (rpcException.code != 1001) {
        // Other RPCErrors are unexpected. Rethrow so it will hit crash
        // logging.
        rethrow;
      }
      _logger.printTrace('DevFS: Creating failed. Destroying and trying again');
      await destroy();
      final vm_service.Response response = await _vmService.createDevFS(fsName);
      _baseUri = Uri.parse(response.json!['uri'] as String);
    }
    _logger.printTrace('DevFS: Created new filesystem on the device ($_baseUri)');
    return _baseUri!;
  }

  Future<void> destroy() async {
    _logger.printTrace('DevFS: Deleting filesystem on the device ($_baseUri)');
    await _vmService.deleteDevFS(fsName);
    _logger.printTrace('DevFS: Deleted filesystem on the device ($_baseUri)');
  }

  /// Mark the [lastCompiled] time to the previous successful compile.
  ///
  /// Sometimes a hot reload will be rejected by the VM due to a change in the
  /// structure of the code not supporting the hot reload. In these cases,
  /// the best resolution is a hot restart. However, the resident runner
  /// will not recognize this file as having been changed since the delta
  /// will already have been accepted. Instead, reset the compile time so
  /// that the last updated files are included in subsequent compilations until
  /// a reload is accepted.
  void resetLastCompiled() {
    lastCompiled = _previousCompiled;
  }

  /// Updates files on the device.
  ///
  /// Returns the number of bytes synced.
  ///
  /// If [fullRestart] is true, assumes this is a hot restart instead of a hot
  /// reload. If [resetCompiler] is true, sends a `reset` instruction to the
  /// frontend server.
  Future<UpdateFSReport> update({
    required Uri mainUri,
    required ResidentCompiler generator,
    required bool trackWidgetCreation,
    required String pathToReload,
    required List<Uri> invalidatedFiles,
    required PackageConfig packageConfig,
    required String dillOutputPath,
    required DevelopmentShaderCompiler shaderCompiler,
    DevFSWriter? devFSWriter,
    String? target,
    AssetBundle? bundle,
    bool bundleFirstUpload = false,
    bool fullRestart = false,
    bool resetCompiler = false,
    File? dartPluginRegistrant,
  }) async {
    final candidateCompileTime = DateTime.now();
    lastPackageConfig = packageConfig;

    // Update modified files
    final dirtyEntries = <Uri, DevFSContent>{};
    var assetBuildFailed = false;
    var syncedBytes = 0;
    if (resetCompiler) {
      generator.reset();
    }
    // On a full restart, or on an initial compile for the attach based workflow,
    // this will produce a full dill. Subsequent invocations will produce incremental
    // dill files that depend on the invalidated files.
    _logger.printTrace('Compiling dart to kernel with ${invalidatedFiles.length} updated files');

    // Await the compiler response after checking if the bundle is updated. This allows the file
    // stating to be done while waiting for the frontend_server response.
    final Stopwatch compileTimer = _stopwatchFactory.createStopwatch('compile')..start();
    final Future<CompilerOutput?> pendingCompilerOutput = generator
        .recompile(
          mainUri,
          invalidatedFiles,
          outputPath: dillOutputPath,
          fs: _fileSystem,
          projectRootPath: rootDirectory.path,
          packageConfig: packageConfig,
          checkDartPluginRegistry: true, // The entry point is assumed not to have changed.
          dartPluginRegistrant: dartPluginRegistrant,
        )
        .then((CompilerOutput? result) {
          compileTimer.stop();
          return result;
        });

    if (bundle != null) {
      // Mark processing of bundle started for testability of starting the compile
      // before processing bundle.
      _logger.printTrace('Processing bundle.');
      // await null to give time for telling the compiler to compile.
      await null;

      final String assetDirectory = getAssetBuildDirectory(_config, _fileSystem);
      try {
        final int bundleSyncedBytes = await updateBundle(
          bundle: bundle,
          dirtyEntries: dirtyEntries,
          assetDirectory: assetDirectory,
          assetTransformer: _assetTransformer,
          shaderCompiler: shaderCompiler,
          fileSystem: _fileSystem,
          rootDirectoryPath: rootDirectory.path,
          assetPathsToEvict: assetPathsToEvict,
          shaderPathsToEvict: shaderPathsToEvict,
          bundleFirstUpload: bundleFirstUpload,
          invalidatedFiles: invalidatedFiles,
          onFontManifestUpdated: () => didUpdateFontManifest = true,
        );
        syncedBytes += bundleSyncedBytes;
        _assetTransformer.pruneDependencies(bundle.entries.keys.toSet());
      } on Exception catch (err, stackTrace) {
        _logger.printError('Error updating bundle: $err');
        _logger.printTrace('$stackTrace');
        assetBuildFailed = true;
      }

      // Mark processing of bundle done for testability of starting the compile
      // before processing bundle.
      _logger.printTrace('Bundle processing done.');
    }
    final CompilerOutput? compilerOutput = await pendingCompilerOutput;
    if (compilerOutput == null || compilerOutput.errorCount > 0) {
      return UpdateFSReport();
    }
    // Only update the last compiled time if we successfully compiled.
    _previousCompiled = lastCompiled;
    lastCompiled = candidateCompileTime;
    // list of sources that needs to be monitored are in [compilerOutput.sources]
    sources = <Uri>{
      ...compilerOutput.sources,
      ..._assetTransformer.dependencies.values.expand((Set<Uri> uris) => uris),
    }.toList();
    //
    // Don't send full kernel file that would overwrite what VM already
    // started loading from.
    if (!bundleFirstUpload) {
      final String compiledBinary = compilerOutput.outputFilename;
      if (compiledBinary.isNotEmpty) {
        final Uri entryUri = _fileSystem.path.toUri(pathToReload);
        final content = DevFSFileContent(_fileSystem.file(compiledBinary));
        syncedBytes += content.size;
        dirtyEntries[entryUri] = content;
      }
    }
    _logger.printTrace('Updating files.');
    final Stopwatch transferTimer = _stopwatchFactory.createStopwatch('transfer')..start();

    if (assetBuildFailed) {
      return UpdateFSReport();
    }

    _logger.printTrace('Pending asset builds completed. Writing dirty entries.');
    if (dirtyEntries.isNotEmpty) {
      await (devFSWriter ?? _httpWriter).write(dirtyEntries, _baseUri!, _httpWriter);
    }
    transferTimer.stop();
    _logger.printTrace('DevFS: Sync finished');
    return UpdateFSReport(
      success: true,
      syncedBytes: syncedBytes,
      invalidatedSourcesCount: invalidatedFiles.length,
      compileDuration: compileTimer.elapsed,
      transferDuration: transferTimer.elapsed,
    );
  }

  /// Converts a platform-specific file path to a platform-independent URL path.
  static String _asUriPath(FileSystem fileSystem, String filePath) =>
      '${fileSystem.path.toUri(filePath).path}/';

  /// Process and sync [bundle] assets to [dirtyEntries].
  ///
  /// Returns the total number of bytes processed.
  /// Throws an [Exception] if an asset build failed.
  static Future<int> updateBundle({
    required AssetBundle bundle,
    required Map<Uri, DevFSContent> dirtyEntries,
    required String assetDirectory,
    required DevelopmentAssetTransformer assetTransformer,
    required DevelopmentShaderCompiler shaderCompiler,
    required FileSystem fileSystem,
    required String rootDirectoryPath,
    required Set<String> assetPathsToEvict,
    required Set<String> shaderPathsToEvict,
    required bool bundleFirstUpload,
    List<Uri> invalidatedFiles = const <Uri>[],
    bool syncAllAssetsOnFirstUpload = false,
    void Function()? onFontManifestUpdated,
  }) async {
    final String assetBuildDirPrefix = _asUriPath(fileSystem, assetDirectory);
    final pendingAssetBuilds = <Future<void>>[];
    var syncedBytes = 0;

    final Set<Uri> invalidatedSet = invalidatedFiles.toSet();
    final syncedEntries = <AssetBundleEntry>[];
    bundle.entries.forEach((String archivePath, AssetBundleEntry entry) {
      final bool hasTransformers = entry.transformers.isNotEmpty;
      final bool skipSync = bundleFirstUpload && !syncAllAssetsOnFirstUpload && !hasTransformers;

      if (skipSync) {
        entry.content.markClean();
        return;
      }

      final isShader = entry.kind == AssetKind.shader;
      final bool isEntryModified =
          entry.content.isModified ||
          (isShader && shaderCompiler.areDependenciesModified(entry.content));

      final Set<Uri>? deps = assetTransformer.dependencies[archivePath];
      final bool hasInvalidatedDependencies = deps != null && deps.any(invalidatedSet.contains);

      if (!bundleFirstUpload && !isEntryModified && !hasInvalidatedDependencies) {
        return;
      }
      syncedEntries.add(entry);

      // Modified shaders must be recompiled per-target platform.
      final Uri deviceUri = fileSystem.path.toUri(
        fileSystem.path.join(assetDirectory, archivePath),
      );
      if (deviceUri.path.startsWith(assetBuildDirPrefix)) {
        archivePath = deviceUri.path.substring(assetBuildDirPrefix.length);
      }
      // If the font manifest is updated, invoke the callback so the hot runner
      // can invoke a service extension to force the engine to reload fonts.
      if (archivePath == kFontManifestJson) {
        onFontManifestUpdated?.call();
      }
      switch (entry.kind) {
        case AssetKind.shader:
          pendingAssetBuilds.add(() async {
            DevFSContent content = entry.content;
            if (entry.transformers.isNotEmpty) {
              final DevFSContent? transformed = await assetTransformer.retransformAsset(
                inputAssetKey: archivePath,
                inputAssetContent: content,
                transformerEntries: entry.transformers,
                workingDirectory: rootDirectoryPath,
              );
              if (transformed == null) {
                throw AssetTransformationException(archivePath, 'Failed to transform shader');
              }
              content = transformed;
            }
            if (!bundleFirstUpload || syncAllAssetsOnFirstUpload) {
              final DevFSContent? compiled = await shaderCompiler.recompileShader(content);
              if (compiled == null) {
                throw DevFSShaderCompilationException(archivePath, 'Failed to compile shader');
              }
              dirtyEntries[deviceUri] = compiled;
              syncedBytes += compiled.size;
            }
            if (!bundleFirstUpload) {
              shaderPathsToEvict.add(archivePath);
            }
          }());
        case AssetKind.regular:
        case AssetKind.font:
          pendingAssetBuilds.add(() async {
            DevFSContent? content;
            if (entry.transformers.isEmpty || entry.kind != AssetKind.regular) {
              content = entry.content;
            } else {
              content = await assetTransformer.retransformAsset(
                inputAssetKey: archivePath,
                inputAssetContent: entry.content,
                transformerEntries: entry.transformers,
                workingDirectory: rootDirectoryPath,
              );
            }
            if (content == null) {
              throw AssetTransformationException(archivePath, 'Failed to transform asset');
            }
            if (!bundleFirstUpload || syncAllAssetsOnFirstUpload) {
              dirtyEntries[deviceUri] = content;
              syncedBytes += content.size;
            }
            if (!bundleFirstUpload) {
              assetPathsToEvict.add(archivePath);
            }
          }());
      }
    });

    await Future.wait(pendingAssetBuilds);
    for (final entry in syncedEntries) {
      entry.content.markClean();
    }
    return syncedBytes;
  }
}

/// An implementation of a devFS writer which copies physical files for devices
/// running on the same host.
///
/// DevFS entries which correspond to physical files are copied using [File.copySync],
/// while entries that correspond to arbitrary string/byte values are written from
/// memory.
///
/// Requires that the file system is the same for both the tool and application.
class LocalDevFSWriter implements DevFSWriter {
  LocalDevFSWriter({required FileSystem fileSystem}) : _fileSystem = fileSystem;

  final FileSystem _fileSystem;

  @override
  Future<void> write(Map<Uri, DevFSContent> entries, Uri baseUri, [DevFSWriter? parent]) async {
    try {
      for (final MapEntry<Uri, DevFSContent> entry in entries.entries) {
        final Uri uri = entry.key;
        final DevFSContent devFSContent = entry.value;
        final File destination = _fileSystem.file(baseUri.resolveUri(uri));
        if (!destination.parent.existsSync()) {
          destination.parent.createSync(recursive: true);
        }
        if (devFSContent is DevFSFileContent) {
          final content = devFSContent.file as File;
          content.copySync(destination.path);
          continue;
        }
        destination.writeAsBytesSync(await devFSContent.contentsAsBytes());
      }
    } on FileSystemException catch (err) {
      throw DevFSException(err.toString());
    }
  }
}

/// Exception thrown when development-time asset transformation fails.
final class AssetTransformationException implements Exception {
  AssetTransformationException(this.archivePath, this.message);

  final String archivePath;
  final String message;

  @override
  String toString() => 'AssetTransformationException: $message (Asset: $archivePath)';
}

/// Exception thrown when development-time shader compilation fails.
final class DevFSShaderCompilationException implements Exception {
  DevFSShaderCompilationException(this.archivePath, this.message);

  final String archivePath;
  final String message;

  @override
  String toString() => 'DevFSShaderCompilationException: $message (Shader: $archivePath)';
}
