// 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) {
    final (FileStat? currentStat, _) = _statFile();
    if (_fileStat == null && currentStat == null) {
      return false;
    }
    return _fileStat == null || 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,
          onFontManifestUpdated: () => didUpdateFontManifest = true,
        );
        syncedBytes += bundleSyncedBytes;
      } 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 = compilerOutput.sources;
    //
    // 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,
    bool syncAllAssetsOnFirstUpload = false,
    void Function()? onFontManifestUpdated,
  }) async {
    if (bundleFirstUpload && !syncAllAssetsOnFirstUpload) {
      for (final AssetBundleEntry entry in bundle.entries.values) {
        entry.content.markClean();
      }
      return 0;
    }

    final String assetBuildDirPrefix = _asUriPath(fileSystem, assetDirectory);
    final pendingAssetBuilds = <Future<void>>[];
    var syncedBytes = 0;

    final syncedEntries = <AssetBundleEntry>[];
    bundle.entries.forEach((String archivePath, AssetBundleEntry entry) {
      if (!bundleFirstUpload && !entry.content.isModified) {
        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;
            }
            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');
            }
            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)';
}
