// 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 'dart:typed_data';

import 'package:dwds/data/build_result.dart';
// ignore: import_of_legacy_library_into_null_safe
import 'package:dwds/dwds.dart';
import 'package:html/dom.dart';
import 'package:html/parser.dart';
import 'package:logging/logging.dart' as logging;
import 'package:meta/meta.dart';
import 'package:mime/mime.dart' as mime;
import 'package:package_config/package_config.dart';
import 'package:shelf/shelf.dart' as shelf;
import 'package:shelf/shelf_io.dart' as shelf;
import 'package:vm_service/vm_service.dart' as vm_service;

import '../artifacts.dart';
import '../asset.dart';
import '../base/common.dart';
import '../base/file_system.dart';
import '../base/io.dart';
import '../base/logger.dart';
import '../base/net.dart';
import '../base/platform.dart';
import '../build_info.dart';
import '../build_system/targets/scene_importer.dart';
import '../build_system/targets/shader_compiler.dart';
import '../build_system/targets/web.dart';
import '../bundle_builder.dart';
import '../cache.dart';
import '../compile.dart';
import '../convert.dart';
import '../dart/package_map.dart';
import '../devfs.dart';
import '../globals.dart' as globals;
import '../project.dart';
import '../vmservice.dart';
import '../web/bootstrap.dart';
import '../web/chrome.dart';
import '../web/compile.dart';
import '../web/file_generators/flutter_js.dart' as flutter_js;
import '../web/memory_fs.dart';
import 'sdk_web_configuration.dart';

typedef DwdsLauncher = Future<Dwds> Function({
  required AssetReader assetReader,
  required Stream<BuildResult> buildResults,
  required ConnectionProvider chromeConnection,
  required LoadStrategy loadStrategy,
  required bool enableDebugging,
  ExpressionCompiler? expressionCompiler,
  bool enableDebugExtension,
  String hostname,
  bool useSseForDebugProxy,
  bool useSseForDebugBackend,
  bool useSseForInjectedClient,
  UrlEncoder? urlEncoder,
  bool spawnDds,
  bool enableDevtoolsLaunch,
  DevtoolsLauncher? devtoolsLauncher,
  bool launchDevToolsInNewWindow,
  SdkConfigurationProvider? sdkConfigurationProvider,
  bool emitDebugEvents,
});

// A minimal index for projects that do not yet support web.
const String _kDefaultIndex = '''
<html>
    <head>
        <base href="/">
    </head>
    <body>
        <script src="main.dart.js"></script>
    </body>
</html>
''';

/// An expression compiler connecting to FrontendServer.
///
/// This is only used in development mode.
class WebExpressionCompiler implements ExpressionCompiler {
  WebExpressionCompiler(this._generator, {
    required FileSystem fileSystem,
  }) : _fileSystem = fileSystem;

  final ResidentCompiler _generator;
  final FileSystem _fileSystem;

  @override
  Future<ExpressionCompilationResult> compileExpressionToJs(
    String isolateId,
    String libraryUri,
    int line,
    int column,
    Map<String, String> jsModules,
    Map<String, String> jsFrameValues,
    String moduleName,
    String expression,
  ) async {
    final CompilerOutput? compilerOutput =
        await _generator.compileExpressionToJs(libraryUri, line, column,
            jsModules, jsFrameValues, moduleName, expression);

    if (compilerOutput != null) {
      final String content = utf8.decode(
          _fileSystem.file(compilerOutput.outputFilename).readAsBytesSync());
      return ExpressionCompilationResult(
          content, compilerOutput.errorCount > 0);
    }

    return ExpressionCompilationResult(
        "InternalError: frontend server failed to compile '$expression'",
        true);
  }

  @override
  Future<void> initialize({String? moduleFormat, bool? soundNullSafety}) async {}

  @override
  Future<bool> updateDependencies(Map<String, ModuleInfo> modules) async => true;
}

/// A web server which handles serving JavaScript and assets.
///
/// This is only used in development mode.
class WebAssetServer implements AssetReader {
  @visibleForTesting
  WebAssetServer(
    this._httpServer,
    this._packages,
    this.internetAddress,
    this._modules,
    this._digests,
    this._nullSafetyMode,
  ) : basePath = _parseBasePathFromIndexHtml(globals.fs.currentDirectory
            .childDirectory('web')
            .childFile('index.html'));

  // Fallback to "application/octet-stream" on null which
  // makes no claims as to the structure of the data.
  static const String _kDefaultMimeType = 'application/octet-stream';

  final Map<String, String> _modules;
  final Map<String, String> _digests;

  int get selectedPort => _httpServer.port;

  void performRestart(List<String> modules) {
    for (final String module in modules) {
      // We skip computing the digest by using the hashCode of the underlying buffer.
      // Whenever a file is updated, the corresponding Uint8List.view it corresponds
      // to will change.
      final String moduleName =
          module.startsWith('/') ? module.substring(1) : module;
      final String name = moduleName.replaceAll('.lib.js', '');
      final String path = moduleName.replaceAll('.js', '');
      _modules[name] = path;
      _digests[name] = _webMemoryFS.files[moduleName].hashCode.toString();
    }
  }

  @visibleForTesting
  List<String> write(
    File codeFile,
    File manifestFile,
    File sourcemapFile,
    File metadataFile,
  ) {
    return _webMemoryFS.write(codeFile, manifestFile, sourcemapFile, metadataFile);
  }

  /// Start the web asset server on a [hostname] and [port].
  ///
  /// If [testMode] is true, do not actually initialize dwds or the shelf static
  /// server.
  ///
  /// Unhandled exceptions will throw a [ToolExit] with the error and stack
  /// trace.
  static Future<WebAssetServer> start(
    ChromiumLauncher? chromiumLauncher,
    String hostname,
    int? port,
    UrlTunneller? urlTunneller,
    bool useSseForDebugProxy,
    bool useSseForDebugBackend,
    bool useSseForInjectedClient,
    BuildInfo buildInfo,
    bool enableDwds,
    bool enableDds,
    Uri entrypoint,
    ExpressionCompiler? expressionCompiler,
    NullSafetyMode nullSafetyMode, {
    bool testMode = false,
    DwdsLauncher dwdsLauncher = Dwds.start,
  }) async {
    InternetAddress address;
    if (hostname == 'any') {
      address = InternetAddress.anyIPv4;
    } else {
      address = (await InternetAddress.lookup(hostname)).first;
    }
    HttpServer? httpServer;
    const int kMaxRetries = 4;
    for (int i = 0; i <= kMaxRetries; i++) {
      try {
        httpServer = await HttpServer.bind(address, port ?? await globals.os.findFreePort());
        break;
      } on SocketException catch (e, s) {
        if (i >= kMaxRetries) {
          globals.printError('Failed to bind web development server:\n$e', stackTrace: s);
          throwToolExit('Failed to bind web development server:\n$e');
        }
        await Future<void>.delayed(const Duration(milliseconds: 100));
      }
    }

    // Allow rendering in a iframe.
    httpServer!.defaultResponseHeaders.remove('x-frame-options', 'SAMEORIGIN');

    final PackageConfig packageConfig = buildInfo.packageConfig;
    final Map<String, String> digests = <String, String>{};
    final Map<String, String> modules = <String, String>{};
    final WebAssetServer server = WebAssetServer(
      httpServer,
      packageConfig,
      address,
      modules,
      digests,
      nullSafetyMode,
    );
    if (testMode) {
      return server;
    }

    // In release builds deploy a simpler proxy server.
    if (buildInfo.mode != BuildMode.debug) {
      final ReleaseAssetServer releaseAssetServer = ReleaseAssetServer(
        entrypoint,
        fileSystem: globals.fs,
        platform: globals.platform,
        flutterRoot: Cache.flutterRoot,
        webBuildDirectory: getWebBuildDirectory(),
        basePath: server.basePath,
      );
      runZonedGuarded(() {
        shelf.serveRequests(httpServer!, releaseAssetServer.handle);
      }, (Object e, StackTrace s) {
        globals.printTrace('Release asset server: error serving requests: $e:$s');
      });
      return server;
    }

    // Return a version string for all active modules. This is populated
    // along with the `moduleProvider` update logic.
    Future<Map<String, String>> digestProvider() async => digests;

    // Ensure dwds is present and provide middleware to avoid trying to
    // load the through the isolate APIs.
    final Directory directory =
        await _loadDwdsDirectory(globals.fs, globals.logger);
    shelf.Handler middleware(FutureOr<shelf.Response> Function(shelf.Request) innerHandler) {
      return (shelf.Request request) async {
        if (request.url.path.endsWith('dwds/src/injected/client.js')) {
          final Uri uri = directory.uri.resolve('src/injected/client.js');
          final String result =
              await globals.fs.file(uri.toFilePath()).readAsString();
          return shelf.Response.ok(result, headers: <String, String>{
            HttpHeaders.contentTypeHeader: 'application/javascript',
          });
        }
        return innerHandler(request);
      };
    }

    logging.Logger.root.level = logging.Level.ALL;
    logging.Logger.root.onRecord.listen(log);

    // In debug builds, spin up DWDS and the full asset server.
    final Dwds dwds = await dwdsLauncher(
      assetReader: server,
      enableDebugExtension: true,
      buildResults: const Stream<BuildResult>.empty(),
      chromeConnection: () async {
        final Chromium chromium = await chromiumLauncher!.connectedInstance;
        return chromium.chromeConnection;
      },
      hostname: hostname,
      urlEncoder: urlTunneller,
      enableDebugging: true,
      useSseForDebugProxy: useSseForDebugProxy,
      useSseForDebugBackend: useSseForDebugBackend,
      useSseForInjectedClient: useSseForInjectedClient,
      loadStrategy: FrontendServerRequireStrategyProvider(
        ReloadConfiguration.none,
        server,
        PackageUriMapper(packageConfig),
        digestProvider,
        server.basePath!,
      ).strategy,
      expressionCompiler: expressionCompiler,
      spawnDds: enableDds,
      sdkConfigurationProvider: SdkWebConfigurationProvider(globals.artifacts!),
    );
    shelf.Pipeline pipeline = const shelf.Pipeline();
    if (enableDwds) {
      pipeline = pipeline.addMiddleware(middleware);
      pipeline = pipeline.addMiddleware(dwds.middleware);
    }
    final shelf.Handler dwdsHandler =
        pipeline.addHandler(server.handleRequest);
    final shelf.Cascade cascade =
        shelf.Cascade().add(dwds.handler).add(dwdsHandler);
    runZonedGuarded(() {
      shelf.serveRequests(httpServer!, cascade.handler);
    }, (Object e, StackTrace s) {
      globals.printTrace('Dwds server: error serving requests: $e:$s');
    });
    server.dwds = dwds;
    server._dwdsInit = true;
    return server;
  }

  final NullSafetyMode _nullSafetyMode;
  final HttpServer _httpServer;
  final WebMemoryFS _webMemoryFS = WebMemoryFS();
  final PackageConfig _packages;
  final InternetAddress internetAddress;
  late final Dwds dwds;
  late Directory entrypointCacheDirectory;
  bool _dwdsInit = false;

  @visibleForTesting
  HttpHeaders get defaultResponseHeaders => _httpServer.defaultResponseHeaders;

  @visibleForTesting
  Uint8List? getFile(String path) => _webMemoryFS.files[path];

  @visibleForTesting
  Uint8List? getSourceMap(String path) => _webMemoryFS.sourcemaps[path];

  @visibleForTesting
  Uint8List? getMetadata(String path) => _webMemoryFS.metadataFiles[path];

  @visibleForTesting

  /// The base path to serve from.
  ///
  /// It should have no leading or trailing slashes.
  String? basePath = '';

  // handle requests for JavaScript source, dart sources maps, or asset files.
  @visibleForTesting
  Future<shelf.Response> handleRequest(shelf.Request request) async {
    if (request.method != 'GET') {
      // Assets are served via GET only.
      return shelf.Response.notFound('');
    }

    final String? requestPath = _stripBasePath(request.url.path, basePath);

    if (requestPath == null) {
      return shelf.Response.notFound('');
    }

    // If the response is `/`, then we are requesting the index file.
    if (requestPath == '/' || requestPath.isEmpty) {
      return _serveIndex();
    }

    final Map<String, String> headers = <String, String>{};

    // Track etag headers for better caching of resources.
    final String? ifNoneMatch = request.headers[HttpHeaders.ifNoneMatchHeader];
    headers[HttpHeaders.cacheControlHeader] = 'max-age=0, must-revalidate';

    // If this is a JavaScript file, it must be in the in-memory cache.
    // Attempt to look up the file by URI.
    final String webServerPath =
        requestPath.replaceFirst('.dart.js', '.dart.lib.js');
    if (_webMemoryFS.files.containsKey(requestPath) || _webMemoryFS.files.containsKey(webServerPath)) {
      final List<int>? bytes = getFile(requestPath) ?? getFile(webServerPath);
      // Use the underlying buffer hashCode as a revision string. This buffer is
      // replaced whenever the frontend_server produces new output files, which
      // will also change the hashCode.
      final String etag = bytes.hashCode.toString();
      if (ifNoneMatch == etag) {
        return shelf.Response.notModified();
      }
      headers[HttpHeaders.contentLengthHeader] = bytes!.length.toString();
      headers[HttpHeaders.contentTypeHeader] = 'application/javascript';
      headers[HttpHeaders.etagHeader] = etag;
      return shelf.Response.ok(bytes, headers: headers);
    }
    // If this is a sourcemap file, then it might be in the in-memory cache.
    // Attempt to lookup the file by URI.
    if (_webMemoryFS.sourcemaps.containsKey(requestPath)) {
      final List<int>? bytes = getSourceMap(requestPath);
      final String etag = bytes.hashCode.toString();
      if (ifNoneMatch == etag) {
        return shelf.Response.notModified();
      }
      headers[HttpHeaders.contentLengthHeader] = bytes!.length.toString();
      headers[HttpHeaders.contentTypeHeader] = 'application/json';
      headers[HttpHeaders.etagHeader] = etag;
      return shelf.Response.ok(bytes, headers: headers);
    }

    // If this is a metadata file, then it might be in the in-memory cache.
    // Attempt to lookup the file by URI.
    if (_webMemoryFS.metadataFiles.containsKey(requestPath)) {
      final List<int>? bytes = getMetadata(requestPath);
      final String etag = bytes.hashCode.toString();
      if (ifNoneMatch == etag) {
        return shelf.Response.notModified();
      }
      headers[HttpHeaders.contentLengthHeader] = bytes!.length.toString();
      headers[HttpHeaders.contentTypeHeader] = 'application/json';
      headers[HttpHeaders.etagHeader] = etag;
      return shelf.Response.ok(bytes, headers: headers);
    }

    File file = _resolveDartFile(requestPath);

    // If all of the lookups above failed, the file might have been an asset.
    // Try and resolve the path relative to the built asset directory.
    if (!file.existsSync()) {
      final Uri potential = globals.fs
          .directory(getAssetBuildDirectory())
          .uri
          .resolve(requestPath.replaceFirst('assets/', ''));
      file = globals.fs.file(potential);
    }

    if (!file.existsSync()) {
      final Uri webPath = globals.fs.currentDirectory
          .childDirectory('web')
          .uri
          .resolve(requestPath);
      file = globals.fs.file(webPath);
    }

    if (!file.existsSync()) {
      // Paths starting with these prefixes should've been resolved above.
      if (requestPath.startsWith('assets/') ||
          requestPath.startsWith('packages/')) {
        return shelf.Response.notFound('');
      }
      return _serveIndex();
    }

    // For real files, use a serialized file stat plus path as a revision.
    // This allows us to update between canvaskit and non-canvaskit SDKs.
    final String etag = file.lastModifiedSync().toIso8601String() +
        Uri.encodeComponent(file.path);
    if (ifNoneMatch == etag) {
      return shelf.Response.notModified();
    }

    final int length = file.lengthSync();
    // Attempt to determine the file's mime type. if this is not provided some
    // browsers will refuse to render images/show video etc. If the tool
    // cannot determine a mime type, fall back to application/octet-stream.
    final String mimeType = mime.lookupMimeType(
        file.path,
        headerBytes: await file.openRead(0, mime.defaultMagicNumbersMaxLength).first,
    ) ?? _kDefaultMimeType;

    headers[HttpHeaders.contentLengthHeader] = length.toString();
    headers[HttpHeaders.contentTypeHeader] = mimeType;
    headers[HttpHeaders.etagHeader] = etag;
    return shelf.Response.ok(file.openRead(), headers: headers);
  }

  /// Tear down the http server running.
  Future<void> dispose() async {
    if (_dwdsInit) {
      await dwds.stop();
    }
    return _httpServer.close();
  }

  /// Write a single file into the in-memory cache.
  void writeFile(String filePath, String contents) {
    writeBytes(filePath, utf8.encode(contents) as Uint8List);
  }

  void writeBytes(String filePath, Uint8List contents) {
    _webMemoryFS.files[filePath] = contents;
  }

  /// Determines what rendering backed to use.
  WebRendererMode webRenderer = WebRendererMode.html;

  shelf.Response _serveIndex() {
    final Map<String, String> headers = <String, String>{
      HttpHeaders.contentTypeHeader: 'text/html',
    };
    final File indexFile = globals.fs.currentDirectory
        .childDirectory('web')
        .childFile('index.html');

    if (indexFile.existsSync()) {
      String indexFileContent =  indexFile.readAsStringSync();
      if (indexFileContent.contains(kBaseHrefPlaceholder)) {
          indexFileContent =  indexFileContent.replaceAll(kBaseHrefPlaceholder, '/');
          headers[HttpHeaders.contentLengthHeader] = indexFileContent.length.toString();
          return shelf.Response.ok(indexFileContent,headers: headers);
        }
      headers[HttpHeaders.contentLengthHeader] =
          indexFile.lengthSync().toString();
      return shelf.Response.ok(indexFile.openRead(), headers: headers);
    }

    headers[HttpHeaders.contentLengthHeader] = _kDefaultIndex.length.toString();
    return shelf.Response.ok(_kDefaultIndex, headers: headers);
  }

  // Attempt to resolve `path` to a dart file.
  File _resolveDartFile(String path) {
    // Return the actual file objects so that local engine changes are automatically picked up.
    switch (path) {
      case 'dart_sdk.js':
        return _resolveDartSdkJsFile;
      case 'dart_sdk.js.map':
        return _resolveDartSdkJsMapFile;
    }
    // This is the special generated entrypoint.
    if (path == 'web_entrypoint.dart') {
      return entrypointCacheDirectory.childFile('web_entrypoint.dart');
    }

    // If this is a dart file, it must be on the local file system and is
    // likely coming from a source map request. The tool doesn't currently
    // consider the case of Dart files as assets.
    final File dartFile =
        globals.fs.file(globals.fs.currentDirectory.uri.resolve(path));
    if (dartFile.existsSync()) {
      return dartFile;
    }

    final List<String> segments = path.split('/');
    if (segments.first.isEmpty) {
      segments.removeAt(0);
    }

    // The file might have been a package file which is signaled by a
    // `/packages/<package>/<path>` request.
    if (segments.first == 'packages') {
      final Uri? filePath = _packages
          .resolve(Uri(scheme: 'package', pathSegments: segments.skip(1)));
      if (filePath != null) {
        final File packageFile = globals.fs.file(filePath);
        if (packageFile.existsSync()) {
          return packageFile;
        }
      }
    }

    // Otherwise it must be a Dart SDK source or a Flutter Web SDK source.
    final Directory dartSdkParent = globals.fs
        .directory(globals.artifacts!.getArtifactPath(
          Artifact.engineDartSdkPath,
          platform: TargetPlatform.web_javascript))
        .parent;
    final File dartSdkFile = globals.fs.file(dartSdkParent.uri.resolve(path));
    if (dartSdkFile.existsSync()) {
      return dartSdkFile;
    }

    final Directory flutterWebSdk = globals.fs
        .directory(globals.artifacts!.getHostArtifact(HostArtifact.flutterWebSdk));
    final File webSdkFile = globals.fs.file(flutterWebSdk.uri.resolve(path));

    return webSdkFile;
  }

  File get _resolveDartSdkJsFile =>
      globals.fs.file(globals.artifacts!.getHostArtifact(
          kDartSdkJsArtifactMap[webRenderer]![_nullSafetyMode]!
      ));

  File get _resolveDartSdkJsMapFile =>
    globals.fs.file(globals.artifacts!.getHostArtifact(
        kDartSdkJsMapArtifactMap[webRenderer]![_nullSafetyMode]!
    ));

  @override
  Future<String?> dartSourceContents(String serverPath) async {
    serverPath = _stripBasePath(serverPath, basePath)!;
    final File result = _resolveDartFile(serverPath);
    if (result.existsSync()) {
      return result.readAsString();
    }
    return null;
  }

  @override
  Future<String> sourceMapContents(String serverPath) async {
    serverPath = _stripBasePath(serverPath, basePath)!;
    return utf8.decode(_webMemoryFS.sourcemaps[serverPath]!);
  }

  @override
  Future<String?> metadataContents(String serverPath) async {
    final String? resultPath = _stripBasePath(serverPath, basePath);
    if (resultPath == 'main_module.ddc_merged_metadata') {
      return _webMemoryFS.mergedMetadata;
    }
    if (_webMemoryFS.metadataFiles.containsKey(resultPath)) {
      return utf8.decode(_webMemoryFS.metadataFiles[resultPath]!);
    }
    throw Exception('Could not find metadata contents for $serverPath');
  }

  @override
  Future<void> close() async {}
}

class ConnectionResult {
  ConnectionResult(this.appConnection, this.debugConnection, this.vmService);

  final AppConnection? appConnection;
  final DebugConnection? debugConnection;
  final vm_service.VmService vmService;
}

typedef VmServiceFactory = Future<vm_service.VmService> Function(
  Uri, {
  CompressionOptions compression,
  required Logger logger,
});

/// The web specific DevFS implementation.
class WebDevFS implements DevFS {
  /// Create a new [WebDevFS] instance.
  ///
  /// [testMode] is true, do not actually initialize dwds or the shelf static
  /// server.
  WebDevFS({
    required this.hostname,
    required int? port,
    required this.packagesFilePath,
    required this.urlTunneller,
    required this.useSseForDebugProxy,
    required this.useSseForDebugBackend,
    required this.useSseForInjectedClient,
    required this.buildInfo,
    required this.enableDwds,
    required this.enableDds,
    required this.entrypoint,
    required this.expressionCompiler,
    required this.chromiumLauncher,
    required this.nullAssertions,
    required this.nativeNullAssertions,
    required this.nullSafetyMode,
    this.testMode = false,
  }) : _port = port;

  final Uri entrypoint;
  final String hostname;
  final String packagesFilePath;
  final UrlTunneller? urlTunneller;
  final bool useSseForDebugProxy;
  final bool useSseForDebugBackend;
  final bool useSseForInjectedClient;
  final BuildInfo buildInfo;
  final bool enableDwds;
  final bool enableDds;
  final bool testMode;
  final ExpressionCompiler? expressionCompiler;
  final ChromiumLauncher? chromiumLauncher;
  final bool nullAssertions;
  final bool nativeNullAssertions;
  final int? _port;
  final NullSafetyMode nullSafetyMode;

  late WebAssetServer webAssetServer;

  Dwds get dwds => webAssetServer.dwds;

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

  @override
  bool didUpdateFontManifest = false;

  Future<DebugConnection>? _cachedExtensionFuture;
  StreamSubscription<void>? _connectedApps;

  /// Connect and retrieve the [DebugConnection] for the current application.
  ///
  /// Only calls [AppConnection.runMain] on the subsequent connections.
  Future<ConnectionResult?> connect(
    bool useDebugExtension, {
    @visibleForTesting
    VmServiceFactory vmServiceFactory = createVmServiceDelegate,
  }) {
    final Completer<ConnectionResult> firstConnection =
        Completer<ConnectionResult>();
    // Note there is an asynchronous gap between this being set to true and
    // [firstConnection] completing; thus test the boolean to determine if
    // the current connection is the first.
    bool foundFirstConnection = false;
    _connectedApps =
        dwds.connectedApps.listen((AppConnection appConnection) async {
      try {
        final DebugConnection debugConnection = useDebugExtension
            ? await (_cachedExtensionFuture ??=
                dwds.extensionDebugConnections.stream.first)
            : await dwds.debugConnection(appConnection);
        if (foundFirstConnection) {
          appConnection.runMain();
        } else {
          foundFirstConnection = true;
          final vm_service.VmService vmService = await vmServiceFactory(
            Uri.parse(debugConnection.uri),
            logger: globals.logger,
          );
          firstConnection
              .complete(ConnectionResult(appConnection, debugConnection, vmService));
        }
      } on Exception catch (error, stackTrace) {
        if (!firstConnection.isCompleted) {
          firstConnection.completeError(error, stackTrace);
        }
      }
    }, onError: (Object error, StackTrace stackTrace) {
      globals.printError(
        'Unknown error while waiting for debug connection:$error\n$stackTrace',
      );
      if (!firstConnection.isCompleted) {
        firstConnection.completeError(error, stackTrace);
      }
    });
    return firstConnection.future;
  }

  @override
  List<Uri> sources = <Uri>[];

  @override
  DateTime? lastCompiled;

  @override
  PackageConfig? lastPackageConfig;

  // We do not evict assets on the web.
  @override
  Set<String> get assetPathsToEvict => const <String>{};

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

  @override
  Future<Uri> create() async {
    webAssetServer = await WebAssetServer.start(
      chromiumLauncher,
      hostname,
      _port,
      urlTunneller,
      useSseForDebugProxy,
      useSseForDebugBackend,
      useSseForInjectedClient,
      buildInfo,
      enableDwds,
      enableDds,
      entrypoint,
      expressionCompiler,
      nullSafetyMode,
      testMode: testMode,
    );

    final int selectedPort = webAssetServer.selectedPort;
    if (buildInfo.dartDefines.contains('FLUTTER_WEB_AUTO_DETECT=true')) {
      webAssetServer.webRenderer = WebRendererMode.autoDetect;
    } else if (buildInfo.dartDefines.contains('FLUTTER_WEB_USE_SKIA=true')) {
      webAssetServer.webRenderer = WebRendererMode.canvaskit;
    }
    if (hostname == 'any') {
      _baseUri = Uri.http('localhost:$selectedPort', webAssetServer.basePath!);
    } else {
      _baseUri = Uri.http('$hostname:$selectedPort', webAssetServer.basePath!);
    }
    return _baseUri!;
  }

  @override
  Future<void> destroy() async {
    await webAssetServer.dispose();
    await _connectedApps?.cancel();
  }

  @override
  Uri deviceUriToHostUri(Uri deviceUri) {
    return deviceUri;
  }

  @override
  String get fsName => 'web_asset';

  @override
  Directory? get rootDirectory => null;

  @override
  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,
    DevelopmentSceneImporter? sceneImporter,
    DevFSWriter? devFSWriter,
    String? target,
    AssetBundle? bundle,
    DateTime? firstBuildTime,
    bool bundleFirstUpload = false,
    bool fullRestart = false,
    String? projectRootPath,
    File? dartPluginRegistrant,
  }) async {
    lastPackageConfig = packageConfig;
    final File mainFile = globals.fs.file(mainUri);
    final String outputDirectoryPath = mainFile.parent.path;

    if (bundleFirstUpload) {
      webAssetServer.entrypointCacheDirectory =
          globals.fs.directory(outputDirectoryPath);
      generator.addFileSystemRoot(outputDirectoryPath);
      final String entrypoint = globals.fs.path.basename(mainFile.path);
      webAssetServer.writeBytes(entrypoint, mainFile.readAsBytesSync());
      webAssetServer.writeBytes('require.js', requireJS.readAsBytesSync());
      webAssetServer.writeBytes(
          'stack_trace_mapper.js', stackTraceMapper.readAsBytesSync());
      webAssetServer.writeFile(
          'manifest.json', '{"info":"manifest not generated in run mode."}');
      webAssetServer.writeFile('flutter.js', flutter_js.generateFlutterJsFile());
      webAssetServer.writeFile('flutter_service_worker.js',
          '// Service worker not loaded in run mode.');
      webAssetServer.writeFile(
          'version.json', FlutterProject.current().getVersionInfo());
      webAssetServer.writeFile(
        'main.dart.js',
        generateBootstrapScript(
          requireUrl: 'require.js',
          mapperUrl: 'stack_trace_mapper.js',
        ),
      );
      webAssetServer.writeFile(
        'main_module.bootstrap.js',
        generateMainModule(
          entrypoint: entrypoint,
          nullAssertions: nullAssertions,
          nativeNullAssertions: nativeNullAssertions,
        ),
      );
      // TODO(zanderso): refactor the asset code in this and the regular devfs to
      // be shared.
      if (bundle != null) {
        await writeBundle(
          globals.fs.directory(getAssetBuildDirectory()),
          bundle.entries,
          bundle.entryKinds,
          targetPlatform: TargetPlatform.web_javascript,
        );
      }
    }
    final DateTime candidateCompileTime = DateTime.now();
    if (fullRestart) {
      generator.reset();
    }

    // The tool generates an entrypoint file in a temp directory to handle
    // the web specific bootstrap logic. To make it easier for DWDS to handle
    // mapping the file name, this is done via an additional file root and
    // special hard-coded scheme.
    final CompilerOutput? compilerOutput = await generator.recompile(
      Uri(
        scheme: 'org-dartlang-app',
        path: '/${mainUri.pathSegments.last}',
      ),
      invalidatedFiles,
      outputPath: dillOutputPath,
      packageConfig: packageConfig,
      projectRootPath: projectRootPath,
      fs: globals.fs,
      dartPluginRegistrant: dartPluginRegistrant,
    );
    if (compilerOutput == null || compilerOutput.errorCount > 0) {
      return UpdateFSReport();
    }

    // Only update the last compiled time if we successfully compiled.
    lastCompiled = candidateCompileTime;
    // list of sources that needs to be monitored are in [compilerOutput.sources]
    sources = compilerOutput.sources;
    late File codeFile;
    File manifestFile;
    File sourcemapFile;
    File metadataFile;
    late List<String> modules;
    try {
      final Directory parentDirectory = globals.fs.directory(outputDirectoryPath);
      codeFile = parentDirectory.childFile('${compilerOutput.outputFilename}.sources');
      manifestFile = parentDirectory.childFile('${compilerOutput.outputFilename}.json');
      sourcemapFile = parentDirectory.childFile('${compilerOutput.outputFilename}.map');
      metadataFile = parentDirectory.childFile('${compilerOutput.outputFilename}.metadata');
      modules = webAssetServer._webMemoryFS.write(codeFile, manifestFile, sourcemapFile, metadataFile);
    } on FileSystemException catch (err) {
      throwToolExit('Failed to load recompiled sources:\n$err');
    }
    webAssetServer.performRestart(modules);
    return UpdateFSReport(
      success: true,
      syncedBytes: codeFile.lengthSync(),
      invalidatedSourcesCount: invalidatedFiles.length,
    );
  }

  @visibleForTesting
  final File requireJS = globals.fs.file(globals.fs.path.join(
    globals.artifacts!.getArtifactPath(Artifact.engineDartSdkPath, platform: TargetPlatform.web_javascript),
    'lib',
    'dev_compiler',
    'amd',
    'require.js',
  ));

  @visibleForTesting
  final File stackTraceMapper = globals.fs.file(globals.fs.path.join(
    globals.artifacts!.getArtifactPath(Artifact.engineDartSdkPath, platform: TargetPlatform.web_javascript),
    'lib',
    'dev_compiler',
    'web',
    'dart_stack_trace_mapper.js',
  ));

  @override
  void resetLastCompiled() {
    // Not used for web compilation.
  }

  @override
  Set<String> get shaderPathsToEvict => <String>{};

  @override
  Set<String> get scenePathsToEvict => <String>{};
}

class ReleaseAssetServer {
  ReleaseAssetServer(
    this.entrypoint, {
    required FileSystem fileSystem,
    required String? webBuildDirectory,
    required String? flutterRoot,
    required Platform platform,
    this.basePath = '',
  })  : _fileSystem = fileSystem,
        _platform = platform,
        _flutterRoot = flutterRoot,
        _webBuildDirectory = webBuildDirectory,
        _fileSystemUtils =
            FileSystemUtils(fileSystem: fileSystem, platform: platform);

  final Uri entrypoint;
  final String? _flutterRoot;
  final String? _webBuildDirectory;
  final FileSystem _fileSystem;
  final FileSystemUtils _fileSystemUtils;
  final Platform _platform;

  @visibleForTesting

  /// The base path to serve from.
  ///
  /// It should have no leading or trailing slashes.
  final String? basePath;

  // Locations where source files, assets, or source maps may be located.
  List<Uri> _searchPaths() => <Uri>[
        _fileSystem.directory(_webBuildDirectory).uri,
        _fileSystem.directory(_flutterRoot).uri,
        _fileSystem.directory(_flutterRoot).parent.uri,
        _fileSystem.currentDirectory.uri,
        _fileSystem.directory(_fileSystemUtils.homeDirPath).uri,
      ];

  Future<shelf.Response> handle(shelf.Request request) async {
    if (request.method != 'GET') {
      // Assets are served via GET only.
      return shelf.Response.notFound('');
    }

    Uri? fileUri;
    final String? requestPath = _stripBasePath(request.url.path, basePath);

    if (requestPath == null) {
      return shelf.Response.notFound('');
    }

    if (request.url.toString() == 'main.dart') {
      fileUri = entrypoint;
    } else {
      for (final Uri uri in _searchPaths()) {
        final Uri potential = uri.resolve(requestPath);
        if (!_fileSystem.isFileSync(
                potential.toFilePath(windows: _platform.isWindows))) {
          continue;
        }
        fileUri = potential;
        break;
      }
    }
    if (fileUri != null) {
      final File file = _fileSystem.file(fileUri);
      final Uint8List bytes = file.readAsBytesSync();
      // Fallback to "application/octet-stream" on null which
      // makes no claims as to the structure of the data.
      final String mimeType =
          mime.lookupMimeType(file.path, headerBytes: bytes) ??
              'application/octet-stream';
      return shelf.Response.ok(bytes, headers: <String, String>{
        'Content-Type': mimeType,
      });
    }

    final File file = _fileSystem
        .file(_fileSystem.path.join(_webBuildDirectory!, 'index.html'));
    return shelf.Response.ok(file.readAsBytesSync(), headers: <String, String>{
      'Content-Type': 'text/html',
    });
  }
}

@visibleForTesting
void log(logging.LogRecord event) {
  final String error = event.error == null? '': 'Error: ${event.error}';
  if (event.level >= logging.Level.SEVERE) {
    globals.printError('${event.loggerName}: ${event.message}$error', stackTrace: event.stackTrace);
  } else if (event.level == logging.Level.WARNING) {
    // Note: Temporary fix for https://github.com/flutter/flutter/issues/109792
    // TODO(annagrin): Remove the condition after the bogus warning is
    // removed in dwds: https://github.com/dart-lang/webdev/issues/1722
    if (!event.message.contains('No module for')) {
      globals.printWarning('${event.loggerName}: ${event.message}$error');
    }
  } else  {
    globals.printTrace('${event.loggerName}: ${event.message}$error');
  }
}

Future<Directory> _loadDwdsDirectory(
    FileSystem fileSystem, Logger logger) async {
  final String toolPackagePath =
      fileSystem.path.join(Cache.flutterRoot!, 'packages', 'flutter_tools');
  final String packageFilePath =
      fileSystem.path.join(toolPackagePath, '.dart_tool', 'package_config.json');
  final PackageConfig packageConfig = await loadPackageConfigWithLogging(
    fileSystem.file(packageFilePath),
    logger: logger,
  );
  return fileSystem.directory(packageConfig['dwds']!.packageUriRoot);
}

String? _stripBasePath(String path, String? basePath) {
  path = _stripLeadingSlashes(path);
  if (basePath != null && path.startsWith(basePath)) {
    path = path.substring(basePath.length);
  } else {
    // The given path isn't under base path, return null to indicate that.
    return null;
  }
  return _stripLeadingSlashes(path);
}

String _stripLeadingSlashes(String path) {
  while (path.startsWith('/')) {
    path = path.substring(1);
  }
  return path;
}

String _stripTrailingSlashes(String path) {
  while (path.endsWith('/')) {
    path = path.substring(0, path.length - 1);
  }
  return path;
}

String? _parseBasePathFromIndexHtml(File indexHtml) {
  final String htmlContent =
      indexHtml.existsSync() ? indexHtml.readAsStringSync() : _kDefaultIndex;
  final Document document = parse(htmlContent);
  final Element? baseElement = document.querySelector('base');
  String? baseHref =
      baseElement?.attributes == null ? null : baseElement!.attributes['href'];

  if (baseHref == null || baseHref == kBaseHrefPlaceholder) {
    baseHref = '';
  } else if (!baseHref.startsWith('/')) {
    throw ToolExit(
      'Error: The base href in "web/index.html" must be absolute (i.e. start '
      'with a "/"), but found: `${baseElement!.outerHtml}`.\n'
      '$basePathExample',
    );
  } else if (!baseHref.endsWith('/')) {
    throw ToolExit(
      'Error: The base href in "web/index.html" must end with a "/", but found: `${baseElement!.outerHtml}`.\n'
      '$basePathExample',
    );
  } else {
    baseHref = _stripLeadingSlashes(_stripTrailingSlashes(baseHref));
  }

  return baseHref;
}

const String basePathExample = '''
For example, to serve from the root use:

    <base href="/">

To serve from a subpath "foo" (i.e. http://localhost:8080/foo/ instead of http://localhost:8080/) use:

    <base href="/foo/">

For more information, see: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/base
''';
