// 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:vm_service/vm_service.dart' as vm_service;

import 'artifacts.dart';
import 'asset.dart';
import 'base/config.dart';
import 'base/file_system.dart';
import 'base/io.dart';
import 'base/logger.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 'context/tool_context.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;
}

/// 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, {this._devFSConfig});

  final FileSystemEntity file;
  final DevFSConfig? _devFSConfig;
  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 this._osUtils,
    required HttpClient httpClient,
    required this._logger,
    this._uploadRetryThrottle,
  }) : httpAddress = serviceProtocol.httpAddress,
       _client = httpClient;

  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({
    this._success = false,
    this._invalidatedSourcesCount = 0,
    this._syncedBytes = 0,
    this._scannedSourcesCount = 0,
    this._compileDuration = Duration.zero,
    this._transferDuration = Duration.zero,
    this._findInvalidatedDuration = Duration.zero,
    this._hotReloadRejected = false,
  });

  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 BuildMode buildMode,
    required ToolContext toolContext,
    HttpClient? httpClient,
    this._stopwatchFactory = const StopwatchFactory(),
    Duration? uploadRetryThrottle,
  }) : _toolContext = toolContext,
       _vmService = serviceProtocol,
       _httpWriter = _DevFSHttpWriter(
         fsName,
         serviceProtocol,
         osUtils: toolContext.os,
         logger: toolContext.logger,
         uploadRetryThrottle: uploadRetryThrottle,
         httpClient: httpClient ?? HttpClient(),
       ),
       _assetTransformer = DevelopmentAssetTransformer(
         transformer: AssetTransformer(
           processManager: toolContext.processManager,
           fileSystem: toolContext.fs,
           dartBinaryPath: toolContext.artifacts.getArtifactPath(Artifact.engineDartBinary),
           buildMode: buildMode,
         ),
         fileSystem: toolContext.fs,
         logger: toolContext.logger,
       );

  final ToolContext _toolContext;
  final FlutterVmService _vmService;
  final _DevFSHttpWriter _httpWriter;
  final StopwatchFactory _stopwatchFactory;
  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 {
    final Logger logger = _toolContext.logger;
    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 {
    final Logger logger = _toolContext.logger;
    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 ToolContext(:Config config, :FileSystem fs, :Logger logger) = _toolContext;
    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: fs,
          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, fs);
      try {
        final int bundleSyncedBytes = await updateBundle(
          bundle: bundle,
          dirtyEntries: dirtyEntries,
          assetDirectory: assetDirectory,
          assetTransformer: _assetTransformer,
          shaderCompiler: shaderCompiler,
          fileSystem: fs,
          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 = fs.path.toUri(pathToReload);
        final content = DevFSFileContent(fs.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 this._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)';
}
