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

import '../application_package.dart';
import '../artifacts.dart';
import '../base/common.dart';
import '../base/context.dart';
import '../base/file_system.dart';
import '../base/io.dart';
import '../base/logger.dart';
import '../base/net.dart';
import '../base/platform.dart';
import '../base/process.dart';
import '../base/time.dart';
import '../build_info.dart';
import '../device.dart';
import '../device_port_forwarder.dart';
import '../device_vm_service_discovery_for_attach.dart';
import '../globals.dart' as globals;
import '../project.dart';
import '../runner/flutter_command.dart';
import '../vmservice.dart';

import 'application_package.dart';
import 'fuchsia_ffx.dart';
import 'fuchsia_pm.dart';
import 'fuchsia_sdk.dart';
import 'fuchsia_workflow.dart';
import 'pkgctl.dart';

/// The [FuchsiaDeviceTools] instance.
FuchsiaDeviceTools get fuchsiaDeviceTools => context.get<FuchsiaDeviceTools>()!;

/// Fuchsia device-side tools.
class FuchsiaDeviceTools {
  late final FuchsiaPkgctl pkgctl = FuchsiaPkgctl();
  late final FuchsiaFfx ffx = FuchsiaFfx();
}

final String _ipv4Loopback = InternetAddress.loopbackIPv4.address;
final String _ipv6Loopback = InternetAddress.loopbackIPv6.address;

// Enables testing the fuchsia isolate discovery
Future<FlutterVmService> _kDefaultFuchsiaIsolateDiscoveryConnector(Uri uri) {
  return connectToVmService(uri, logger: globals.logger);
}

Future<void> _kDefaultDartDevelopmentServiceStarter(
  Device device,
  Uri vmServiceUri,
  bool disableServiceAuthCodes,
) async {
  await device.dds.startDartDevelopmentService(
    vmServiceUri,
    hostPort: 0,
    ipv6: true,
    disableServiceAuthCodes: disableServiceAuthCodes,
    logger: globals.logger,
  );
}

/// Read the log for a particular device.
class _FuchsiaLogReader extends DeviceLogReader {
  _FuchsiaLogReader(this._device, this._systemClock, [this._app]);

  // \S matches non-whitespace characters.
  static final RegExp _flutterLogOutput = RegExp(r'INFO: \S+\(flutter\): ');

  final FuchsiaDevice _device;
  final ApplicationPackage? _app;
  final SystemClock _systemClock;

  @override
  String get name => _device.name;

  Stream<String>? _logLines;
  @override
  Stream<String> get logLines {
    final Stream<String>? logStream = globals.fuchsiaSdk?.syslogs(_device.id);
    _logLines ??= _processLogs(logStream);
    return _logLines ?? const Stream<String>.empty();
  }

  Stream<String>? _processLogs(Stream<String>? lines) {
    if (lines == null) {
      return null;
    }
    // Get the starting time of the log processor to filter logs from before
    // the process attached.
    final DateTime startTime = _systemClock.now();
    // Determine if line comes from flutter, and optionally whether it matches
    // the correct fuchsia module.
    final ApplicationPackage? app = _app;
    final RegExp matchRegExp = app == null
        ? _flutterLogOutput
        : RegExp('INFO: ${app.name}(\\.cm)?\\(flutter\\): ');
    return Stream<String>.eventTransformed(
      lines,
      (EventSink<String> output) => _FuchsiaLogSink(output, matchRegExp, startTime),
    );
  }

  @override
  String toString() => name;

  @override
  void dispose() {
    // The Fuchsia SDK syslog process is killed when the subscription to the
    // logLines Stream is canceled.
  }
}

class _FuchsiaLogSink implements EventSink<String> {
  _FuchsiaLogSink(this._outputSink, this._matchRegExp, this._startTime);

  static final RegExp _utcDateOutput = RegExp(r'\d+\-\d+\-\d+ \d+:\d+:\d+');
  final EventSink<String> _outputSink;
  final RegExp _matchRegExp;
  final DateTime _startTime;

  @override
  void add(String line) {
    if (!_matchRegExp.hasMatch(line)) {
      return;
    }
    final String? rawDate = _utcDateOutput.firstMatch(line)?.group(0);
    if (rawDate == null) {
      return;
    }
    final DateTime logTime = DateTime.parse(rawDate);
    if (logTime.millisecondsSinceEpoch < _startTime.millisecondsSinceEpoch) {
      return;
    }
    _outputSink.add(
        '[${logTime.toLocal()}] Flutter: ${line.split(_matchRegExp).last}');
  }

  @override
  void addError(Object error, [StackTrace? stackTrace]) {
    _outputSink.addError(error, stackTrace);
  }

  @override
  void close() {
    _outputSink.close();
  }
}

/// Device discovery for Fuchsia devices.
class FuchsiaDevices extends PollingDeviceDiscovery {
  FuchsiaDevices({
    required Platform platform,
    required FuchsiaWorkflow fuchsiaWorkflow,
    required FuchsiaSdk fuchsiaSdk,
    required Logger logger,
  }) : _platform = platform,
       _fuchsiaWorkflow = fuchsiaWorkflow,
       _fuchsiaSdk = fuchsiaSdk,
       _logger = logger,
       super('Fuchsia devices');

  final Platform _platform;
  final FuchsiaWorkflow _fuchsiaWorkflow;
  final FuchsiaSdk _fuchsiaSdk;
  final Logger _logger;

  @override
  bool get supportsPlatform => isFuchsiaSupportedPlatform(_platform);

  @override
  bool get canListAnything => _fuchsiaWorkflow.canListDevices;

  @override
  Future<List<Device>> pollingGetDevices({ Duration? timeout }) async {
    if (!_fuchsiaWorkflow.canListDevices) {
      return <Device>[];
    }
    // TODO(omerlevran): Remove once soft transition is complete fxb/67602.
    final List<String>? text = (await _fuchsiaSdk.listDevices(
      timeout: timeout,
    ))?.split('\n');
    if (text == null || text.isEmpty) {
      return <Device>[];
    }
    final List<FuchsiaDevice> devices = <FuchsiaDevice>[];
    for (final String line in text) {
      final FuchsiaDevice? device = await _parseDevice(line);
      if (device == null) {
        continue;
      }
      devices.add(device);
    }
    return devices;
  }

  @override
  Future<List<String>> getDiagnostics() async => const <String>[];

  Future<FuchsiaDevice?> _parseDevice(String text) async {
    final String line = text.trim();
    // ['ip', 'device name']
    final List<String> words = line.split(' ');
    if (words.length < 2) {
      return null;
    }
    final String name = words[1];

    // TODO(omerlevran): Add support for resolve on the FuchsiaSdk Object.
    final String? resolvedHost = await _fuchsiaSdk.fuchsiaFfx.resolve(name);
    if (resolvedHost == null) {
      _logger.printError('Failed to resolve host for Fuchsia device `$name`');
      return null;
    }
    return FuchsiaDevice(resolvedHost, name: name);
  }

  @override
  List<String> get wellKnownIds => const <String>[];
}

class FuchsiaDevice extends Device {
  FuchsiaDevice(super.id, {required this.name})
      : super(
          platformType: PlatformType.fuchsia,
          category: null,
          ephemeral: true,
        );

  @override
  bool get supportsHotReload => true;

  @override
  bool get supportsHotRestart => false;

  @override
  bool get supportsFlutterExit => false;

  @override
  final String name;

  @override
  Future<bool> get isLocalEmulator async => false;

  @override
  Future<String?> get emulatorId async => null;

  @override
  bool get supportsStartPaused => false;

  late final Future<bool> isSession = _initIsSession();

  /// Determine if the Fuchsia device is running a session based build.
  ///
  /// If the device is running a session based build, `ffx session` should be
  /// used to launch apps. Fuchsia flutter apps cannot currently be launched
  /// without a session.
  Future<bool> _initIsSession() async {
    return await globals.fuchsiaSdk?.fuchsiaFfx.sessionShow() != null;
  }

  @override
  Future<bool> isAppInstalled(
    ApplicationPackage app, {
    String? userIdentifier,
  }) async => false;

  @override
  Future<bool> isLatestBuildInstalled(ApplicationPackage app) async => false;

  @override
  Future<bool> installApp(
    ApplicationPackage app, {
    String? userIdentifier,
  }) => Future<bool>.value(false);

  @override
  Future<bool> uninstallApp(
    ApplicationPackage app, {
    String? userIdentifier,
  }) async => false;

  @override
  bool isSupported() => true;

  @override
  bool supportsRuntimeMode(BuildMode buildMode) =>
      buildMode != BuildMode.jitRelease;

  @override
  Future<LaunchResult> startApp(
    FuchsiaApp package, {
    String? mainPath,
    String? route,
    required DebuggingOptions debuggingOptions,
    Map<String, Object?> platformArgs = const <String, Object?>{},
    bool prebuiltApplication = false,
    bool ipv6 = false,
    String? userIdentifier,
  }) async {
    if (await isSession) {
      globals.printTrace('Running on a session framework based build.');
    } else {
      globals.printTrace('Running on a non session framework based build.');
    }

    if (!prebuiltApplication) {
      throwToolExit(
        'This tool does not currently build apps for fuchsia.\n'
        'Build the app using a supported Fuchsia workflow.\n'
        'Then use the --${FlutterOptions.kUseApplicationBinary} flag.'
      );
    }
    // Stop the app if it's currently running.
    await stopApp(package);

    // Find out who the device thinks we are.
    final int port = await globals.os.findFreePort();
    if (port == 0) {
      globals.printError('Failed to find a free port');
      return LaunchResult.failed();
    }

    // Try Start with a fresh package repo in case one was left over from a
    // previous run.
    final Directory packageRepo = globals.fs.directory(
        globals.fs.path.join(getFuchsiaBuildDirectory(), '.pkg-repo'));
    try {
      if (packageRepo.existsSync()) {
        packageRepo.deleteSync(recursive: true);
      }
      packageRepo.createSync(recursive: true);
    } on Exception catch (e) {
      globals.printError('Failed to create Fuchsia package repo directory '
          'at ${packageRepo.path}: $e');
      return LaunchResult.failed();
    }

    final String appName = FlutterProject.current().manifest.appName;
    final Status status = globals.logger.startProgress(
      'Starting Fuchsia application $appName...',
    );
    FuchsiaPackageServer? fuchsiaPackageServer;
    bool serverRegistered = false;
    String fuchsiaUrl;
    try {
      // Start up a package server.
      const String packageServerName = FuchsiaPackageServer.toolHost;
      fuchsiaPackageServer =
          FuchsiaPackageServer(packageRepo.path, packageServerName, '', port);
      if (!await fuchsiaPackageServer.start()) {
        globals.printError('Failed to start the Fuchsia package server');
        return LaunchResult.failed();
      }

      // Serve the application's package.
      final File farArchive =
          package.farArchive(debuggingOptions.buildInfo.mode);
      if (!await fuchsiaPackageServer.addPackage(farArchive)) {
        globals.printError('Failed to add package to the package server');
        return LaunchResult.failed();
      }

      // Serve the flutter_runner.
      final File flutterRunnerArchive =
          globals.fs.file(globals.artifacts!.getArtifactPath(
        Artifact.fuchsiaFlutterRunner,
        platform: await targetPlatform,
        mode: debuggingOptions.buildInfo.mode,
      ));
      if (!await fuchsiaPackageServer.addPackage(flutterRunnerArchive)) {
        globals.printError(
            'Failed to add flutter_runner package to the package server');
        return LaunchResult.failed();
      }

      // Teach the package controller about the package server.
      if (!await fuchsiaDeviceTools.pkgctl
          .addRepo(this, fuchsiaPackageServer)) {
        globals.printError('Failed to teach amber about the package server');
        return LaunchResult.failed();
      }
      serverRegistered = true;

      // Tell the package controller to prefetch the flutter_runner.
      String flutterRunnerName;
      if (debuggingOptions.buildInfo.usesAot) {
        if (debuggingOptions.buildInfo.mode.isRelease) {
          flutterRunnerName = 'flutter_aot_product_runner';
        } else {
          flutterRunnerName = 'flutter_aot_runner';
        }
      } else {
        if (debuggingOptions.buildInfo.mode.isRelease) {
          flutterRunnerName = 'flutter_jit_product_runner';
        } else {
          flutterRunnerName = 'flutter_jit_runner';
        }
      }

      if (!await fuchsiaDeviceTools.pkgctl
          .resolve(this, fuchsiaPackageServer.name, flutterRunnerName)) {
        globals
            .printError('Failed to get pkgctl to prefetch the flutter_runner');
        return LaunchResult.failed();
      }

      // Tell the package controller to prefetch the app.
      if (!await fuchsiaDeviceTools.pkgctl
          .resolve(this, fuchsiaPackageServer.name, appName)) {
        globals.printError('Failed to get pkgctl to prefetch the package');
        return LaunchResult.failed();
      }

      fuchsiaUrl = 'fuchsia-pkg://$packageServerName/$appName#meta/$appName.cm';

      if (await isSession) {
        // Instruct ffx session to start the app
        final bool addedApp =
            await globals.fuchsiaSdk?.fuchsiaFfx.sessionAdd(fuchsiaUrl) ?? false;
        if (!addedApp) {
          globals.printError('Failed to add the app via `ffx session add`');
          return LaunchResult.failed();
        }
      } else {
        globals.printError(
            'Fuchsia flutter apps can only be launched within a session');
        return LaunchResult.failed();
      }
    } finally {
      // Try to un-teach the package controller about the package server if
      // needed.
      if (serverRegistered && fuchsiaPackageServer != null) {
        await fuchsiaDeviceTools.pkgctl.rmRepo(this, fuchsiaPackageServer);
      }
      // Shutdown the package server and delete the package repo;
      globals.printTrace("Shutting down the tool's package server.");
      fuchsiaPackageServer?.stop();
      globals.printTrace(
          "Removing the tool's package repo: at ${packageRepo.path}");
      try {
        packageRepo.deleteSync(recursive: true);
      } on Exception catch (e) {
        globals.printError('Failed to remove Fuchsia package repo directory '
            'at ${packageRepo.path}: $e.');
      }
      status.cancel();
    }

    if (debuggingOptions.buildInfo.mode.isRelease) {
      globals.printTrace('App successfully started in a release mode.');
      return LaunchResult.succeeded();
    }
    globals.printTrace(
        'App started in a non-release mode. Setting up vmservice connection.');

    // In a debug or profile build, try to find the vmService uri.
    final FuchsiaIsolateDiscoveryProtocol discovery =
        getIsolateDiscoveryProtocol(appName);
    try {
      final Uri vmServiceUri = await discovery.uri;
      return LaunchResult.succeeded(vmServiceUri: vmServiceUri);
    } finally {
      discovery.dispose();
    }
  }

  @override
  Future<bool> stopApp(
    ApplicationPackage? app, {
    String? userIdentifier,
  }) async {
    if (await isSession) {
      // Currently there are no way to close a running app programmatically
      // using the session framework afaik. So this is a no-op.
      return true;
    }
    // Fuchsia flutter apps currently require a session, but if that changes,
    // add the relevant "stopApp" code here.
    return true;
  }

  Future<TargetPlatform> _queryTargetPlatform() async {
    const TargetPlatform defaultTargetPlatform = TargetPlatform.fuchsia_arm64;
    if (!globals.fuchsiaArtifacts!.hasSshConfig) {
      globals.printTrace('Could not determine Fuchsia target platform because '
          'Fuchsia ssh configuration is missing.\n'
          'Defaulting to arm64.');
      return defaultTargetPlatform;
    }
    final RunResult result = await shell('uname -m');
    if (result.exitCode != 0) {
      globals.printError(
          'Could not determine Fuchsia target platform type:\n$result\n'
          'Defaulting to arm64.');
      return defaultTargetPlatform;
    }
    final String machine = result.stdout.trim();
    switch (machine) {
      case 'aarch64':
        return TargetPlatform.fuchsia_arm64;
      case 'x86_64':
        return TargetPlatform.fuchsia_x64;
      default:
        globals.printError('Unknown Fuchsia target platform "$machine". '
            'Defaulting to arm64.');
        return defaultTargetPlatform;
    }
  }

  @override
  bool get supportsScreenshot => isFuchsiaSupportedPlatform(globals.platform);

  @override
  Future<void> takeScreenshot(File outputFile) async {
    if (outputFile.basename.split('.').last != 'ppm') {
      throw Exception('${outputFile.path} must be a .ppm file');
    }
    final RunResult screencapResult =
        await shell('screencap > /tmp/screenshot.ppm');
    if (screencapResult.exitCode != 0) {
      throw Exception(
          'Could not take a screenshot on device $name:\n$screencapResult');
    }
    try {
      final RunResult scpResult =
          await scp('/tmp/screenshot.ppm', outputFile.path);
      if (scpResult.exitCode != 0) {
        throw Exception('Failed to copy screenshot from device:\n$scpResult');
      }
    } finally {
      try {
        final RunResult deleteResult = await shell('rm /tmp/screenshot.ppm');
        if (deleteResult.exitCode != 0) {
          globals.printError(
              'Failed to delete screenshot.ppm from the device:\n$deleteResult');
        }
      } on Exception catch (e) {
        globals
            .printError('Failed to delete screenshot.ppm from the device: $e');
      }
    }
  }

  @override
  late final Future<TargetPlatform> targetPlatform = _queryTargetPlatform();

  @override
  Future<String> get sdkNameAndVersion async {
    const String defaultName = 'Fuchsia';
    if (!globals.fuchsiaArtifacts!.hasSshConfig) {
      globals.printTrace('Could not determine Fuchsia sdk name or version '
          'because Fuchsia ssh configuration is missing.');
      return defaultName;
    }
    const String versionPath = '/pkgfs/packages/build-info/0/data/version';
    final RunResult catResult = await shell('cat $versionPath');
    if (catResult.exitCode != 0) {
      globals.printTrace('Failed to cat $versionPath: ${catResult.stderr}');
      return defaultName;
    }
    final String version = catResult.stdout.trim();
    if (version.isEmpty) {
      globals.printTrace('$versionPath was empty');
      return defaultName;
    }
    return 'Fuchsia $version';
  }

  @override
  DeviceLogReader getLogReader({
    ApplicationPackage? app,
    bool includePastLogs = false,
  }) {
    assert(!includePastLogs, 'Past log reading not supported on Fuchsia.');
    return _logReader ??= _FuchsiaLogReader(this, globals.systemClock, app);
  }

  _FuchsiaLogReader? _logReader;

  @override
  DevicePortForwarder get portForwarder =>
      _portForwarder ??= _FuchsiaPortForwarder(this);
  DevicePortForwarder? _portForwarder;

  @visibleForTesting
  set portForwarder(DevicePortForwarder forwarder) {
    _portForwarder = forwarder;
  }

  @override
  void clearLogs() {}

  @override
  VMServiceDiscoveryForAttach getVMServiceDiscoveryForAttach({
    String? appId,
    String? fuchsiaModule,
    int? filterDevicePort,
    int? expectedHostPort,
    required bool ipv6,
    required Logger logger,
  }) {
    if (fuchsiaModule == null) {
      throwToolExit("'--module' is required for attaching to a Fuchsia device");
    }
    if (expectedHostPort != null) {
      throwToolExit("'--host-vmservice-port' is not supported when attaching to a Fuchsia device");
    }
    return FuchsiaIsolateVMServiceDiscoveryForAttach(getIsolateDiscoveryProtocol(fuchsiaModule));
  }

  /// [true] if the current host address is IPv6.
  late final bool ipv6 = isIPv6Address(id);

  /// Return the address that the device should use to communicate with the
  /// host.
  late final Future<String> hostAddress = () async {
    final RunResult result = await shell(r'echo $SSH_CONNECTION');
    void fail() {
      throwToolExit('Failed to get local address, aborting.\n$result');
    }

    if (result.exitCode != 0) {
      fail();
    }
    final List<String> splitResult = result.stdout.split(' ');
    if (splitResult.isEmpty) {
      fail();
    }
    final String addr = splitResult[0].replaceAll('%', '%25');
    if (addr.isEmpty) {
      fail();
    }
    return addr;
  }();

  /// List the ports currently running a dart vmService.
  Future<List<int>> servicePorts() async {
    const String findCommand = 'find /hub -name vmservice-port';
    final RunResult findResult = await shell(findCommand);
    if (findResult.exitCode != 0) {
      throwToolExit(
          "'$findCommand' on device $name failed. stderr: '${findResult.stderr}'");
    }
    final String findOutput = findResult.stdout;
    if (findOutput.trim() == '') {
      throwToolExit(
          'No Dart Observatories found. Are you running a debug build?');
    }
    final List<int> ports = <int>[];
    for (final String path in findOutput.split('\n')) {
      if (path == '') {
        continue;
      }
      final String lsCommand = 'ls $path';
      final RunResult lsResult = await shell(lsCommand);
      if (lsResult.exitCode != 0) {
        throwToolExit("'$lsCommand' on device $name failed");
      }
      final String lsOutput = lsResult.stdout;
      for (final String line in lsOutput.split('\n')) {
        if (line == '') {
          continue;
        }
        final int? port = int.tryParse(line);
        if (port != null) {
          ports.add(port);
        }
      }
    }
    return ports;
  }

  /// Run `command` on the Fuchsia device shell.
  Future<RunResult> shell(String command) async {
    final File? sshConfig = globals.fuchsiaArtifacts?.sshConfig;
    if (sshConfig == null) {
      throwToolExit('Cannot interact with device. No ssh config.\n'
          'Try setting FUCHSIA_SSH_CONFIG or FUCHSIA_BUILD_DIR.');
    }
    return globals.processUtils.run(<String>[
      'ssh',
      '-F',
      sshConfig.absolute.path,
      id, // Device's IP address.
      command,
    ]);
  }

  /// Transfer the file [origin] from the device to [destination].
  Future<RunResult> scp(String origin, String destination) async {
    final File? sshConfig = globals.fuchsiaArtifacts!.sshConfig;
    if (sshConfig == null) {
      throwToolExit('Cannot interact with device. No ssh config.\n'
          'Try setting FUCHSIA_SSH_CONFIG or FUCHSIA_BUILD_DIR.');
    }
    return globals.processUtils.run(<String>[
      'scp',
      '-F',
      sshConfig.absolute.path,
      '$id:$origin',
      destination,
    ]);
  }

  /// Finds the first port running a VM matching `isolateName` from the
  /// provided set of `ports`.
  ///
  /// Returns null if no isolate port can be found.
  Future<int> findIsolatePort(String isolateName, List<int> ports) async {
    for (final int port in ports) {
      try {
        // The square-bracket enclosure for using the IPv6 loopback
        // didn't appear to work, but when assigning to the IPv4 loopback device,
        // netstat shows that the local port is actually being used on the IPv6
        // loopback (::1).
        final Uri uri = Uri.parse('http://[$_ipv6Loopback]:$port');
        final FlutterVmService vmService =
            await connectToVmService(uri, logger: globals.logger);
        final List<FlutterView> flutterViews =
            await vmService.getFlutterViews();
        for (final FlutterView flutterView in flutterViews) {
          final vm_service.IsolateRef? uiIsolate = flutterView.uiIsolate;
          if (uiIsolate == null) {
            continue;
          }
          final int? port = vmService.httpAddress?.port;
          if (port != null &&
              (uiIsolate.name?.contains(isolateName) ?? false)) {
            return port;
          }
        }
      } on SocketException catch (err) {
        globals.printTrace('Failed to connect to $port: $err');
      }
    }
    throwToolExit('No ports found running $isolateName');
  }

  FuchsiaIsolateDiscoveryProtocol getIsolateDiscoveryProtocol(
      String isolateName) {
    return FuchsiaIsolateDiscoveryProtocol(this, isolateName);
  }

  @override
  bool isSupportedForProject(FlutterProject flutterProject) {
    return flutterProject.fuchsia.existsSync();
  }

  @override
  Future<void> dispose() async {
    await _portForwarder?.dispose();
  }
}

class FuchsiaIsolateVMServiceDiscoveryForAttach extends VMServiceDiscoveryForAttach {
  FuchsiaIsolateVMServiceDiscoveryForAttach(this.isolateDiscoveryProtocol);
  final FuchsiaIsolateDiscoveryProtocol isolateDiscoveryProtocol;

  @override
  Stream<Uri> get uris {
    final Future<Uri> uriFuture = (() async {
      // Wrapping the call in an anonymous async function for easier error handling.
      try {
        return await isolateDiscoveryProtocol.uri;
      } on Exception {
        final FuchsiaDevice device = isolateDiscoveryProtocol._device;
        isolateDiscoveryProtocol.dispose();
        final List<ForwardedPort> ports = device.portForwarder.forwardedPorts.toList();
        for (final ForwardedPort port in ports) {
          await device.portForwarder.unforward(port);
        }
        rethrow;
      }
    })();
    return Stream<Uri>.fromFuture(uriFuture).asBroadcastStream();
  }
}

class FuchsiaIsolateDiscoveryProtocol {
  FuchsiaIsolateDiscoveryProtocol(
    this._device,
    this._isolateName, [
    this._vmServiceConnector = _kDefaultFuchsiaIsolateDiscoveryConnector,
    this._ddsStarter = _kDefaultDartDevelopmentServiceStarter,
    this._pollOnce = false,
  ]);

  static const Duration _pollDuration = Duration(seconds: 10);
  final Map<int, FlutterVmService> _ports = <int, FlutterVmService>{};
  final FuchsiaDevice _device;
  final String _isolateName;
  final Completer<Uri> _foundUri = Completer<Uri>();
  final Future<FlutterVmService> Function(Uri) _vmServiceConnector;
  final Future<void> Function(Device, Uri, bool) _ddsStarter;
  // whether to only poll once.
  final bool _pollOnce;
  Timer? _pollingTimer;
  Status? _status;

  FutureOr<Uri> get uri {
    if (_uri != null) {
      return _uri!;
    }
    _status ??= globals.logger.startProgress(
      'Waiting for a connection from $_isolateName on ${_device.name}...',
    );
    unawaited(_findIsolate()); // Completes the _foundUri Future.
    return _foundUri.future.then((Uri uri) {
      _uri = uri;
      return uri;
    });
  }

  Uri? _uri;

  void dispose() {
    if (!_foundUri.isCompleted) {
      _status?.cancel();
      _status = null;
      _pollingTimer?.cancel();
      _pollingTimer = null;
      _foundUri.completeError(Exception('Did not complete'));
    }
  }

  Future<void> _findIsolate() async {
    final List<int> ports = await _device.servicePorts();
    for (final int port in ports) {
      FlutterVmService? service;
      if (_ports.containsKey(port)) {
        service = _ports[port];
      } else {
        final int localPort = await _device.portForwarder.forward(port);
        try {
          final Uri uri = Uri.parse('http://[$_ipv6Loopback]:$localPort');
          await _ddsStarter(_device, uri, true);
          service = await _vmServiceConnector(_device.dds.uri!);
          _ports[port] = service;
        } on SocketException catch (err) {
          globals.printTrace('Failed to connect to $localPort: $err');
          continue;
        }
      }
      final List<FlutterView> flutterViews =
          await service?.getFlutterViews() ?? <FlutterView>[];
      for (final FlutterView flutterView in flutterViews) {
        final vm_service.IsolateRef? uiIsolate = flutterView.uiIsolate;
        if (uiIsolate == null) {
          continue;
        }
        final int? port = service?.httpAddress?.port;
        if (port != null && (uiIsolate.name?.contains(_isolateName) ?? false)) {
          _foundUri.complete(_device.ipv6
              ? Uri.parse('http://[$_ipv6Loopback]:$port/')
              : Uri.parse('http://$_ipv4Loopback:$port/'));
          _status?.stop();
          return;
        }
      }
    }
    if (_pollOnce) {
      _foundUri.completeError(Exception('Max iterations exceeded'));
      _status?.stop();
      return;
    }
    _pollingTimer = Timer(_pollDuration, _findIsolate);
  }
}

class _FuchsiaPortForwarder extends DevicePortForwarder {
  _FuchsiaPortForwarder(this.device);

  final FuchsiaDevice device;
  final Map<int, Process> _processes = <int, Process>{};

  @override
  Future<int> forward(int devicePort, {int? hostPort}) async {
    hostPort ??= await globals.os.findFreePort();
    if (hostPort == 0) {
      throwToolExit(
          'Failed to forward port $devicePort. No free host-side ports');
    }
    final File? sshConfig = globals.fuchsiaArtifacts?.sshConfig;
    if (sshConfig == null) {
      throwToolExit('Cannot interact with device. No ssh config.\n'
          'Try setting FUCHSIA_SSH_CONFIG or FUCHSIA_BUILD_DIR.');
    }
    // The provided command works around a bug in -N, see US-515
    // for more explanation.
    final List<String> command = <String>[
      'ssh',
      '-6',
      '-F',
      sshConfig.absolute.path,
      '-nNT',
      '-vvv',
      '-f',
      '-L',
      '$hostPort:$_ipv4Loopback:$devicePort',
      device.id, // Device's IP address.
      'true',
    ];
    final Process process = await globals.processManager.start(command);
    unawaited(process.exitCode.then((int exitCode) {
      if (exitCode != 0) {
        throwToolExit('Failed to forward port:$devicePort');
      }
    }));
    _processes[hostPort] = process;
    _forwardedPorts.add(ForwardedPort(hostPort, devicePort));
    return hostPort;
  }

  @override
  List<ForwardedPort> get forwardedPorts => _forwardedPorts;
  final List<ForwardedPort> _forwardedPorts = <ForwardedPort>[];

  @override
  Future<void> unforward(ForwardedPort forwardedPort) async {
    _forwardedPorts.remove(forwardedPort);
    final Process? process = _processes.remove(forwardedPort.hostPort);
    process?.kill();
    final File? sshConfig = globals.fuchsiaArtifacts?.sshConfig;
    if (sshConfig == null) {
      // Nothing to cancel.
      return;
    }
    final List<String> command = <String>[
      'ssh',
      '-F',
      sshConfig.absolute.path,
      '-O',
      'cancel',
      '-vvv',
      '-L',
      '${forwardedPort.hostPort}:$_ipv4Loopback:${forwardedPort.devicePort}',
      device.id, // Device's IP address.
    ];
    final ProcessResult result = await globals.processManager.run(command);
    if (result.exitCode != 0) {
      throwToolExit(
        'Unforward command failed:\n'
        'stdout: ${result.stdout}\n'
        'stderr: ${result.stderr}',
      );
    }
  }

  @override
  Future<void> dispose() async {
    final List<ForwardedPort> forwardedPortsCopy =
        List<ForwardedPort>.of(forwardedPorts);
    for (final ForwardedPort port in forwardedPortsCopy) {
      await unforward(port);
    }
  }
}
