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

/// @docImport 'dart:io';
library;

import 'dart:async';

import 'package:meta/meta.dart' show visibleForTesting;
import 'package:vm_service/vm_service.dart' as vm_service;

import 'base/common.dart';
import 'base/context.dart';
import 'base/io.dart' as io;
import 'base/logger.dart';
import 'base/utils.dart';
import 'cache.dart';
import 'convert.dart';
import 'device.dart';
import 'globals.dart' as globals;
import 'project.dart';
import 'version.dart';

const kResultType = 'type';
const kResultTypeSuccess = 'Success';
const kError = 'error';

const kSetAssetBundlePathMethod = '_flutter.setAssetBundlePath';
const kFlushUIThreadTasksMethod = '_flutter.flushUIThreadTasks';
const kRunInViewMethod = '_flutter.runInView';
const kListViewsMethod = '_flutter.listViews';
const kScreenshotSkpMethod = '_flutter.screenshotSkp';
const kReloadAssetFonts = '_flutter.reloadAssetFonts';

const kFlutterToolAlias = 'Flutter Tools';

const kReloadSourcesServiceName = 'reloadSources';
const kHotRestartServiceName = 'hotRestart';
const kFlutterVersionServiceName = 'flutterVersion';
const kCompileExpressionServiceName = 'compileExpression';
const kFlutterMemoryInfoServiceName = 'flutterMemoryInfo';

/// The error response code from an unrecoverable compilation failure.
const kIsolateReloadBarred = 1005;

/// Used to build RegExp instances which can detect the VM service message.
final kVMServiceMessageRegExp = RegExp(
  r'The Dart VM service is listening on ((http|//)[a-zA-Z0-9:/=_\-\.\[\]]+)',
);

/// Override `WebSocketConnector` in [context] to use a different constructor
/// for [io.WebSocket]s (used by tests).
typedef WebSocketConnector = Future<io.WebSocket> Function(
  String url, {
  io.CompressionOptions compression,
  required Logger logger,
});

typedef PrintStructuredErrorLogMethod = void Function(vm_service.Event);

WebSocketConnector _openChannel = _defaultOpenChannel;

/// A testing only override of the WebSocket connector.
///
/// Provide a `null` value to restore the original connector.
@visibleForTesting
set openChannelForTesting(WebSocketConnector? connector) {
  _openChannel = connector ?? _defaultOpenChannel;
}

/// A function that reacts to the invocation of the 'reloadSources' service.
///
/// The VM Service Protocol allows clients to register custom services that
/// can be invoked by other clients through the service protocol itself.
///
/// Clients like VmService use external 'reloadSources' services,
/// when available, instead of the VM internal one. This allows these clients to
/// invoke Flutter HotReload when connected to a Flutter Application started in
/// hot mode.
///
/// See: https://github.com/dart-lang/sdk/issues/30023
typedef ReloadSources = Future<void> Function(String isolateId, {bool force, bool pause});

typedef Restart = Future<void> Function({bool pause});

typedef CompileExpression = Future<String> Function(
  String isolateId,
  String expression,
  List<String> definitions,
  List<String> definitionTypes,
  List<String> typeDefinitions,
  List<String> typeBounds,
  List<String> typeDefaults,
  String libraryUri,
  String? klass,
  String? method,
  bool isStatic,
);

Future<io.WebSocket> _defaultOpenChannel(
  String url, {
  io.CompressionOptions compression = io.CompressionOptions.compressionDefault,
  required Logger logger,
}) async {
  var delay = const Duration(milliseconds: 100);
  var attempts = 0;
  io.WebSocket? socket;

  Future<void> handleError(Object? e) async {
    void Function(String) printVisibleTrace = logger.printTrace;
    if (attempts == 10) {
      logger.printStatus('Connecting to the VM Service is taking longer than expected...');
    } else if (attempts == 20) {
      logger.printStatus('Still attempting to connect to the VM Service...');
      logger.printStatus(
        'If you do NOT see the Flutter application running, it might have '
        'crashed. The device logs (e.g. from adb or XCode) might have more '
        'details.',
      );
      logger.printStatus(
        'If you do see the Flutter application running on the device, try '
        're-running with --host-vmservice-port to use a specific port known to '
        'be available.',
      );
    } else if (attempts % 50 == 0) {
      printVisibleTrace = logger.printStatus;
    }

    printVisibleTrace('Exception attempting to connect to the VM Service: $e');
    printVisibleTrace('This was attempt #$attempts. Will retry in $delay.');

    // Delay next attempt.
    await Future<void>.delayed(delay);

    // Back off exponentially, up to 1600ms per attempt.
    if (delay < const Duration(seconds: 1)) {
      delay *= 2;
    }
  }

  final WebSocketConnector constructor =
      context.get<WebSocketConnector>() ??
      (
        String url, {
        io.CompressionOptions compression = io.CompressionOptions.compressionDefault,
        Logger? logger,
      }) => io.WebSocket.connect(url, compression: compression);

  while (socket == null) {
    attempts += 1;
    try {
      socket = await constructor(url, compression: compression, logger: logger);
    } on io.IOException catch (e) {
      await handleError(e);
    }
  }
  return socket;
}

/// Override `VMServiceConnector` in [context] to return a different
/// [vm_service.VmService] from [connectToVmService] (used by tests).
typedef VMServiceConnector = Future<FlutterVmService> Function(
  Uri httpUri, {
  ReloadSources? reloadSources,
  Restart? restart,
  CompileExpression? compileExpression,
  FlutterProject? flutterProject,
  PrintStructuredErrorLogMethod? printStructuredErrorLogMethod,
  io.CompressionOptions compression,
  Device? device,
  required Logger logger,
});

/// Set up the VM Service client by attaching services for each of the provided
/// callbacks.
///
/// All parameters besides [vmService] may be null.
Future<vm_service.VmService> setUpVmService({
  ReloadSources? reloadSources,
  Restart? restart,
  CompileExpression? compileExpression,
  Device? device,
  FlutterProject? flutterProject,
  PrintStructuredErrorLogMethod? printStructuredErrorLogMethod,
  required vm_service.VmService vmService,
}) async {
  // Each service registration requires a request to the attached VM service. Since the
  // order of these requests does not matter, store each future in a list and await
  // all at the end of this method.
  final registrationRequests = <Future<vm_service.Success?>>[];
  if (reloadSources != null) {
    vmService.registerServiceCallback(kReloadSourcesServiceName, (
      Map<String, Object?> params,
    ) async {
      final String isolateId = _validateRpcStringParam('reloadSources', params, 'isolateId');
      final bool force = _validateRpcBoolParam('reloadSources', params, 'force');
      final bool pause = _validateRpcBoolParam('reloadSources', params, 'pause');

      await reloadSources(isolateId, force: force, pause: pause);

      return <String, Object>{
        'result': <String, Object>{kResultType: kResultTypeSuccess},
      };
    });
    registrationRequests.add(
      vmService.registerService(kReloadSourcesServiceName, kFlutterToolAlias),
    );
  }

  if (restart != null) {
    vmService.registerServiceCallback(kHotRestartServiceName, (Map<String, Object?> params) async {
      final bool pause = _validateRpcBoolParam('compileExpression', params, 'pause');
      await restart(pause: pause);
      return <String, Object>{
        'result': <String, Object>{kResultType: kResultTypeSuccess},
      };
    });
    registrationRequests.add(vmService.registerService(kHotRestartServiceName, kFlutterToolAlias));
  }

  vmService.registerServiceCallback(kFlutterVersionServiceName, (
    Map<String, Object?> params,
  ) async {
    final FlutterVersion version =
        context.get<FlutterVersion>() ??
        FlutterVersion(fs: globals.fs, flutterRoot: Cache.flutterRoot!, git: globals.git);
    final Map<String, Object> versionJson = version.toJson();
    versionJson['frameworkRevisionShort'] = version.frameworkRevisionShort;
    versionJson['engineRevisionShort'] = version.engineRevisionShort;
    return <String, Object>{
      'result': <String, Object>{kResultType: kResultTypeSuccess, ...versionJson},
    };
  });
  registrationRequests.add(
    vmService.registerService(kFlutterVersionServiceName, kFlutterToolAlias),
  );

  if (compileExpression != null) {
    vmService.registerServiceCallback(kCompileExpressionServiceName, (
      Map<String, Object?> params,
    ) async {
      final String isolateId = _validateRpcStringParam('compileExpression', params, 'isolateId');
      final String expression = _validateRpcStringParam('compileExpression', params, 'expression');
      final definitions = List<String>.from(params['definitions']! as List<Object?>);
      final definitionTypes = List<String>.from(params['definitionTypes']! as List<Object?>);
      final typeDefinitions = List<String>.from(params['typeDefinitions']! as List<Object?>);
      final typeBounds = List<String>.from(params['typeBounds']! as List<Object?>);
      final typeDefaults = List<String>.from(params['typeDefaults']! as List<Object?>);
      final libraryUri = params['libraryUri']! as String;
      final klass = params['klass'] as String?;
      final method = params['method'] as String?;
      final bool isStatic = _validateRpcBoolParam('compileExpression', params, 'isStatic');

      try {
        final String kernelBytesBase64 = await compileExpression(
          isolateId,
          expression,
          definitions,
          definitionTypes,
          typeDefinitions,
          typeBounds,
          typeDefaults,
          libraryUri,
          klass,
          method,
          isStatic,
        );
        return <String, Object>{
          kResultType: kResultTypeSuccess,
          'result': <String, String>{'kernelBytes': kernelBytesBase64},
        };
      } on VmServiceExpressionCompilationException catch (e) {
        // In most situations, we'd just let VmService catch this exception and
        // build the error response. However, in this case we build the error
        // response manually and return it to avoid including the stack trace
        // from the tool in the response, instead returning the compilation
        // error message in the 'details' property of the returned error object.
        return <String, Object>{
          kError: vm_service.RPCError.withDetails(
            'compileExpression',
            vm_service.RPCErrorKind.kExpressionCompilationError.code,
            vm_service.RPCErrorKind.kExpressionCompilationError.message,
            details: e.errorMessage,
          ).toMap(),
        };
      }
    });
    registrationRequests.add(
      vmService.registerService(kCompileExpressionServiceName, kFlutterToolAlias),
    );
  }
  if (device != null) {
    vmService.registerServiceCallback(kFlutterMemoryInfoServiceName, (
      Map<String, Object?> params,
    ) async {
      final MemoryInfo result = await device.queryMemoryInfo();
      return <String, Object>{
        'result': <String, Object>{kResultType: kResultTypeSuccess, ...result.toJson()},
      };
    });
    registrationRequests.add(
      vmService.registerService(kFlutterMemoryInfoServiceName, kFlutterToolAlias),
    );
  }

  if (printStructuredErrorLogMethod != null) {
    vmService.onExtensionEvent.listen(printStructuredErrorLogMethod);
    registrationRequests.add(
      vmService
          .streamListen(vm_service.EventStreams.kExtension)
          .then<vm_service.Success?>(
            (vm_service.Success success) => success,
            // It is safe to ignore this error because we expect an error to be
            // thrown if we're already subscribed.
            onError: (Object error, StackTrace stackTrace) {
              if (error is vm_service.RPCError) {
                return null;
              }
              return Future<vm_service.Success?>.error(error, stackTrace);
            },
          ),
    );
  }

  try {
    await Future.wait(registrationRequests);
  } on vm_service.RPCError catch (e) {
    if (e.isConnectionDisposedException) {
      rethrow;
    }
    throwToolExit('Failed to register service methods on attached VM Service: $e');
  }
  return vmService;
}

/// Connect to a Dart VM Service at [httpUri].
///
/// If the [reloadSources] parameter is not null, the 'reloadSources' service
/// will be registered. The VM Service Protocol allows clients to register
/// custom services that can be invoked by other clients through the service
/// protocol itself.
///
/// See: https://github.com/dart-lang/sdk/commit/df8bf384eb815cf38450cb50a0f4b62230fba217
Future<FlutterVmService> connectToVmService(
  Uri httpUri, {
  ReloadSources? reloadSources,
  Restart? restart,
  CompileExpression? compileExpression,
  FlutterProject? flutterProject,
  PrintStructuredErrorLogMethod? printStructuredErrorLogMethod,
  io.CompressionOptions compression = io.CompressionOptions.compressionDefault,
  Device? device,
  required Logger logger,
}) async {
  final VMServiceConnector connector = context.get<VMServiceConnector>() ?? _connect;
  return connector(
    httpUri,
    reloadSources: reloadSources,
    restart: restart,
    compileExpression: compileExpression,
    compression: compression,
    device: device,
    flutterProject: flutterProject,
    printStructuredErrorLogMethod: printStructuredErrorLogMethod,
    logger: logger,
  );
}

Future<vm_service.VmService> createVmServiceDelegate(
  Uri wsUri, {
  io.CompressionOptions compression = io.CompressionOptions.compressionDefault,
  required Logger logger,
}) async {
  final io.WebSocket channel = await _openChannel(
    wsUri.toString(),
    compression: compression,
    logger: logger,
  );
  return vm_service.VmService(
    channel,
    channel.add,
    disposeHandler: () async {
      await channel.close();
    },
  );
}

Future<FlutterVmService> _connect(
  Uri httpUri, {
  ReloadSources? reloadSources,
  Restart? restart,
  CompileExpression? compileExpression,
  FlutterProject? flutterProject,
  PrintStructuredErrorLogMethod? printStructuredErrorLogMethod,
  io.CompressionOptions compression = io.CompressionOptions.compressionDefault,
  Device? device,
  required Logger logger,
}) async {
  final Uri wsUri = httpUri.replace(scheme: 'ws', path: urlContext.join(httpUri.path, 'ws'));
  final vm_service.VmService delegateService = await createVmServiceDelegate(
    wsUri,
    compression: compression,
    logger: logger,
  );

  final vm_service.VmService service = await setUpVmService(
    reloadSources: reloadSources,
    restart: restart,
    compileExpression: compileExpression,
    device: device,
    flutterProject: flutterProject,
    printStructuredErrorLogMethod: printStructuredErrorLogMethod,
    vmService: delegateService,
  );

  // This call is to ensure we are able to establish a connection instead of
  // keeping on trucking and failing farther down the process.
  await delegateService.getVersion();
  return FlutterVmService(service, httpAddress: httpUri, wsAddress: wsUri);
}

String _validateRpcStringParam(String methodName, Map<String, Object?> params, String paramName) {
  final Object? value = params[paramName];
  if (value is! String || value.isEmpty) {
    throw vm_service.RPCError(
      methodName,
      vm_service.RPCErrorKind.kInvalidParams.code,
      "Invalid '$paramName': $value",
    );
  }
  return value;
}

bool _validateRpcBoolParam(String methodName, Map<String, Object?> params, String paramName) {
  final Object? value = params[paramName];
  if (value != null && value is! bool) {
    throw vm_service.RPCError(
      methodName,
      vm_service.RPCErrorKind.kInvalidParams.code,
      "Invalid '$paramName': $value",
    );
  }
  return (value as bool?) ?? false;
}

/// Peered to an Android/iOS FlutterView widget on a device.
class FlutterView {
  FlutterView({required this.id, required this.uiIsolate});

  factory FlutterView.parse(Map<String, Object?> json) {
    final rawIsolate = json['isolate'] as Map<String, Object?>?;
    vm_service.IsolateRef? isolate;
    if (rawIsolate != null) {
      rawIsolate['number'] = rawIsolate['number']?.toString();
      isolate = vm_service.IsolateRef.parse(rawIsolate);
    }
    return FlutterView(id: json['id']! as String, uiIsolate: isolate);
  }

  final vm_service.IsolateRef? uiIsolate;
  final String id;

  bool get hasIsolate => uiIsolate != null;

  @override
  String toString() => id;

  Map<String, Object?> toJson() {
    return <String, Object?>{'id': id, 'isolate': uiIsolate?.toJson()};
  }
}

/// Flutter specific VM Service functionality.
class FlutterVmService {
  FlutterVmService(this.service, {this.wsAddress, this.httpAddress});

  final vm_service.VmService service;
  final Uri? wsAddress;
  final Uri? httpAddress;

  /// Calls [vm_service.VmService.getVM]. However, in the case that an [vm_service.RPCError]
  /// is thrown due to the service being disconnected, the error is discarded
  /// and null is returned.
  Future<vm_service.VM?> getVmGuarded() async {
    try {
      return await service.getVM();
    } on vm_service.RPCError catch (err) {
      if (err.isConnectionDisposedException) {
        globals.printTrace('VmService.getVm call failed: $err');
        return null;
      }
      rethrow;
    }
  }

  Future<vm_service.Response?> callMethodWrapper(
    String method, {
    String? isolateId,
    Map<String, Object?>? args,
  }) async {
    try {
      return await service.callMethod(method, isolateId: isolateId, args: args);
    } on vm_service.RPCError catch (e) {
      // If the service disappears mid-request the tool is unable to recover
      // and should begin to shutdown due to the service connection closing.
      // Swallow the exception here and let the shutdown logic elsewhere deal
      // with cleaning up.
      if (e.isConnectionDisposedException) {
        return null;
      }
      rethrow;
    }
  }

  /// Set the asset directory for the an attached Flutter view.
  Future<void> setAssetDirectory({
    required Uri assetsDirectory,
    required String? viewId,
    required String? uiIsolateId,
    required bool windows,
  }) async {
    await callMethodWrapper(
      kSetAssetBundlePathMethod,
      isolateId: uiIsolateId,
      args: <String, Object?>{
        'viewId': viewId,
        'assetDirectory': assetsDirectory.toFilePath(windows: windows),
      },
    );
  }

  /// Flush all tasks on the UI thread for an attached Flutter view.
  ///
  /// This method is currently used only for benchmarking.
  Future<void> flushUIThreadTasks({required String uiIsolateId}) async {
    await callMethodWrapper(
      kFlushUIThreadTasksMethod,
      args: <String, String>{'isolateId': uiIsolateId},
    );
  }

  /// Launch the Dart isolate with entrypoint [main] in the Flutter engine [viewId]
  /// with [assetsDirectory] as the devFS.
  ///
  /// This method is used by the tool to hot restart an already running Flutter
  /// engine.
  Future<void> runInView({
    required String viewId,
    required Uri main,
    required Uri assetsDirectory,
  }) async {
    try {
      await service.streamListen(vm_service.EventStreams.kIsolate);
    } on vm_service.RPCError catch (e) {
      // Do nothing if the tool is already subscribed.
      if (e.code != vm_service.RPCErrorKind.kStreamAlreadySubscribed.code) {
        rethrow;
      }
    }

    final Future<void> onRunnable = service.onIsolateEvent.firstWhere((vm_service.Event event) {
      return event.kind == vm_service.EventKind.kIsolateRunnable;
    });
    await callMethodWrapper(
      kRunInViewMethod,
      args: <String, Object>{
        'viewId': viewId,
        'mainScript': main.toString(),
        'assetDirectory': assetsDirectory.toString(),
      },
    );
    await onRunnable;
  }

  Future<String> flutterDebugDumpApp({required String isolateId}) async {
    final Map<String, Object?>? response = await invokeFlutterExtensionRpcRaw(
      'ext.flutter.debugDumpApp',
      isolateId: isolateId,
    );
    return response?['data']?.toString() ?? '';
  }

  Future<String> flutterDebugDumpRenderTree({required String isolateId}) async {
    final Map<String, Object?>? response = await invokeFlutterExtensionRpcRaw(
      'ext.flutter.debugDumpRenderTree',
      isolateId: isolateId,
      args: <String, Object>{},
    );
    return response?['data']?.toString() ?? '';
  }

  Future<String> flutterDebugDumpLayerTree({required String isolateId}) async {
    final Map<String, Object?>? response = await invokeFlutterExtensionRpcRaw(
      'ext.flutter.debugDumpLayerTree',
      isolateId: isolateId,
    );
    return response?['data']?.toString() ?? '';
  }

  Future<String> flutterDebugDumpFocusTree({required String isolateId}) async {
    final Map<String, Object?>? response = await invokeFlutterExtensionRpcRaw(
      'ext.flutter.debugDumpFocusTree',
      isolateId: isolateId,
    );
    return response?['data']?.toString() ?? '';
  }

  Future<String> flutterDebugDumpSemanticsTreeInTraversalOrder({required String isolateId}) async {
    final Map<String, Object?>? response = await invokeFlutterExtensionRpcRaw(
      'ext.flutter.debugDumpSemanticsTreeInTraversalOrder',
      isolateId: isolateId,
    );
    return response?['data']?.toString() ?? '';
  }

  Future<String> flutterDebugDumpSemanticsTreeInInverseHitTestOrder({
    required String isolateId,
  }) async {
    final Map<String, Object?>? response = await invokeFlutterExtensionRpcRaw(
      'ext.flutter.debugDumpSemanticsTreeInInverseHitTestOrder',
      isolateId: isolateId,
    );
    if (response != null) {
      return response['data']?.toString() ?? '';
    }
    return '';
  }

  Future<Map<String, Object?>?> _flutterToggle(String name, {required String isolateId}) async {
    Map<String, Object?>? state = await invokeFlutterExtensionRpcRaw(
      'ext.flutter.$name',
      isolateId: isolateId,
    );
    if (state != null && state.containsKey('enabled') && state['enabled'] is String) {
      state = await invokeFlutterExtensionRpcRaw(
        'ext.flutter.$name',
        isolateId: isolateId,
        args: <String, Object>{'enabled': state['enabled'] == 'true' ? 'false' : 'true'},
      );
    }

    return state;
  }

  Future<Map<String, Object?>?> flutterToggleDebugPaintSizeEnabled({required String isolateId}) =>
      _flutterToggle('debugPaint', isolateId: isolateId);

  Future<Map<String, Object?>?> flutterTogglePerformanceOverlayOverride({
    required String isolateId,
  }) => _flutterToggle('showPerformanceOverlay', isolateId: isolateId);

  Future<Map<String, Object?>?> flutterToggleWidgetInspector({required String isolateId}) =>
      _flutterToggle('inspector.show', isolateId: isolateId);

  Future<Map<String, Object?>?> flutterToggleInvertOversizedImages({required String isolateId}) =>
      _flutterToggle('invertOversizedImages', isolateId: isolateId);

  Future<Map<String, Object?>?> flutterToggleProfileWidgetBuilds({required String isolateId}) =>
      _flutterToggle('profileWidgetBuilds', isolateId: isolateId);

  Future<Map<String, Object?>?> flutterDebugAllowBanner(bool show, {required String isolateId}) {
    return invokeFlutterExtensionRpcRaw(
      'ext.flutter.debugAllowBanner',
      isolateId: isolateId,
      args: <String, Object>{'enabled': show ? 'true' : 'false'},
    );
  }

  Future<Map<String, Object?>?> flutterReassemble({required String? isolateId}) {
    return invokeFlutterExtensionRpcRaw('ext.flutter.reassemble', isolateId: isolateId);
  }

  Future<bool> flutterAlreadyPaintedFirstUsefulFrame({required String isolateId}) async {
    final Map<String, Object?>? result = await invokeFlutterExtensionRpcRaw(
      'ext.flutter.didSendFirstFrameRasterizedEvent',
      isolateId: isolateId,
    );
    // result might be null when the service extension is not initialized
    return result?['enabled'] == 'true';
  }

  Future<Map<String, Object?>?> uiWindowScheduleFrame({required String isolateId}) {
    return invokeFlutterExtensionRpcRaw('ext.ui.window.scheduleFrame', isolateId: isolateId);
  }

  Future<Map<String, Object?>?> flutterEvictAsset(String assetPath, {required String isolateId}) {
    return invokeFlutterExtensionRpcRaw(
      'ext.flutter.evict',
      isolateId: isolateId,
      args: <String, Object?>{'value': assetPath},
    );
  }

  Future<Map<String, Object?>?> flutterEvictShader(String assetPath, {required String isolateId}) {
    return invokeFlutterExtensionRpcRaw(
      'ext.ui.window.reinitializeShader',
      isolateId: isolateId,
      args: <String, Object?>{'assetKey': assetPath},
    );
  }

  /// Reload the Flutter GPU shader library compiled from the shader bundle at
  /// [assetPath].
  ///
  /// Invokes `ext.ui.gpu.reinitializeShaderLibrary`, which the engine registers
  /// lazily on the first `ShaderLibrary.fromAsset` in debug mode and no-ops if
  /// no library is registered at [assetPath]. Returns null when the extension is
  /// not registered (no Flutter GPU shader library has been loaded yet).
  Future<Map<String, Object?>?> flutterReinitializeShaderLibrary(
    String assetPath, {
    required String isolateId,
  }) {
    return invokeFlutterExtensionRpcRaw(
      'ext.ui.gpu.reinitializeShaderLibrary',
      isolateId: isolateId,
      args: <String, Object?>{'assetKey': assetPath},
    );
  }

  /// Exit the application by calling [exit] from `dart:io`.
  ///
  /// This method is only supported by certain embedders. This is
  /// described by [Device.supportsFlutterExit].
  Future<bool> flutterExit({required String isolateId}) async {
    try {
      final Map<String, Object?>? result = await invokeFlutterExtensionRpcRaw(
        'ext.flutter.exit',
        isolateId: isolateId,
      );
      // A response of `null` indicates that `invokeFlutterExtensionRpcRaw` caught an RPCError
      // with a missing method code. This can happen when attempting to quit a Flutter app
      // that never registered the methods in the bindings.
      if (result == null) {
        return false;
      }
    } on vm_service.SentinelException {
      // Do nothing on sentinel, the isolate already exited.
    } on vm_service.RPCError {
      // Do nothing on RPCError, the isolate already exited.
    }
    return true;
  }

  /// Return the current platform override for the flutter view running with
  /// the main isolate [isolateId].
  ///
  /// If a non-null value is provided for [platform], the platform override
  /// is updated with this value.
  Future<String> flutterPlatformOverride({String? platform, required String isolateId}) async {
    final Map<String, Object?>? result = await invokeFlutterExtensionRpcRaw(
      'ext.flutter.platformOverride',
      isolateId: isolateId,
      args: platform != null ? <String, Object>{'value': platform} : <String, String>{},
    );
    if (result case {'value': final String value}) {
      return value;
    }
    return 'unknown';
  }

  /// Return the current brightness value for the flutter view running with
  /// the main isolate [isolateId].
  ///
  /// If a non-null value is provided for [brightness], the brightness override
  /// is updated with this value.
  Future<Brightness?> flutterBrightnessOverride({
    Brightness? brightness,
    required String isolateId,
  }) async {
    final Map<String, Object?>? result = await invokeFlutterExtensionRpcRaw(
      'ext.flutter.brightnessOverride',
      isolateId: isolateId,
      args: brightness != null
          ? <String, String>{'value': brightness.toString()}
          : <String, String>{},
    );
    if (result != null && result['value'] is String) {
      return result['value'] == 'Brightness.light' ? Brightness.light : Brightness.dark;
    }
    return null;
  }

  Future<vm_service.Response?> _checkedCallServiceExtension(
    String method, {
    Map<String, Object?>? args,
  }) async {
    try {
      return await service.callServiceExtension(method, args: args);
    } on vm_service.RPCError catch (err) {
      // If an application is not using the framework or the VM service
      // disappears while handling a request, return null.
      if (err.isServiceExtensionUnregisteredError || err.isConnectionDisposedException) {
        return null;
      }
      rethrow;
    }
  }

  /// Invoke a flutter extension method, if the flutter extension is not
  /// available, returns null.
  Future<Map<String, Object?>?> invokeFlutterExtensionRpcRaw(
    String method, {
    required String? isolateId,
    Map<String, Object?>? args,
  }) async {
    final vm_service.Response? response = await _checkedCallServiceExtension(
      method,
      args: <String, Object?>{'isolateId': ?isolateId, ...?args},
    );
    return response?.json;
  }

  /// List all [FlutterView]s attached to the current VM.
  ///
  /// If this returns an empty list, it will poll forever unless [returnEarly]
  /// is set to true.
  ///
  /// By default, the poll duration is 50 milliseconds.
  Future<List<FlutterView>> getFlutterViews({
    bool returnEarly = false,
    Duration delay = const Duration(milliseconds: 50),
  }) async {
    while (true) {
      final vm_service.Response? response = await callMethodWrapper(kListViewsMethod);
      if (response == null) {
        // The service may have disappeared mid-request.
        // Return an empty list now, and let the shutdown logic elsewhere deal
        // with cleaning up.
        return <FlutterView>[];
      }
      final rawViews = response.json?['views'] as List<Object?>?;
      final views = <FlutterView>[
        if (rawViews != null)
          for (final Map<String, Object?> rawView in rawViews.whereType<Map<String, Object?>>())
            FlutterView.parse(rawView),
      ];
      if (views.isNotEmpty || returnEarly) {
        return views;
      }
      await Future<void>.delayed(delay);
    }
  }

  /// Tell the provided flutter view that the font manifest has been updated
  /// and asset fonts should be reloaded.
  Future<void> reloadAssetFonts({required String isolateId, required String viewId}) async {
    try {
      await callMethodWrapper(
        kReloadAssetFonts,
        isolateId: isolateId,
        args: <String, Object?>{'viewId': viewId},
      );
    } on vm_service.RPCError catch (e) {
      if (e.code == vm_service.RPCErrorKind.kMethodNotFound.code) {
        // Some platforms or embedders (like web) may not implement this VM
        // service protocol method. Just ignore the error and return.
        return;
      }
      rethrow;
    }
  }

  /// Waits for a signal from the VM service that [extensionName] is registered.
  ///
  /// Looks at the list of loaded extensions for first Flutter view, as well as
  /// the stream of added extensions to avoid races.
  ///
  /// Throws a [VmServiceDisappearedException] should the VM Service disappear
  /// while making calls to it.
  Future<vm_service.IsolateRef> findExtensionIsolate(String extensionName) async {
    try {
      await service.streamListen(vm_service.EventStreams.kIsolate);
    } on vm_service.RPCError {
      // Do nothing, since the tool is already subscribed.
    }

    final extensionAdded = Completer<vm_service.IsolateRef>();
    late final StreamSubscription<vm_service.Event> isolateEvents;
    isolateEvents = service.onIsolateEvent.listen((vm_service.Event event) {
      if (event.kind == vm_service.EventKind.kServiceExtensionAdded &&
          event.extensionRPC == extensionName) {
        isolateEvents.cancel();
        extensionAdded.complete(event.isolate!);
      }
    });

    try {
      final List<vm_service.IsolateRef> refs = await _getIsolateRefs();
      for (final ref in refs) {
        final vm_service.Isolate? isolate = await getIsolateOrNull(ref.id!);
        if (isolate != null && (isolate.extensionRPCs?.contains(extensionName) ?? false)) {
          return ref;
        }
      }
      return await extensionAdded.future;
    } on vm_service.RPCError {
      // Translate this exception into something the outer layer understands
      throw VmServiceDisappearedException();
    } finally {
      await isolateEvents.cancel();
    }
  }

  Future<List<vm_service.IsolateRef>> _getIsolateRefs() async {
    final List<FlutterView> flutterViews = await getFlutterViews();
    if (flutterViews.isEmpty) {
      throw VmServiceDisappearedException();
    }

    return <vm_service.IsolateRef>[
      for (final FlutterView flutterView in flutterViews)
        if (flutterView.uiIsolate case final vm_service.IsolateRef uiIsolate) uiIsolate,
    ];
  }

  /// Attempt to retrieve the isolate with id [isolateId], or `null` if it has
  /// been collected.
  Future<vm_service.Isolate?> getIsolateOrNull(String isolateId) async {
    return service
        .getIsolate(isolateId)
        .then<vm_service.Isolate?>(
          (vm_service.Isolate isolate) => isolate,
          onError: (Object? error, StackTrace stackTrace) {
            if (error is vm_service.SentinelException ||
                error == null ||
                (error is vm_service.RPCError &&
                    error.code == vm_service.RPCErrorKind.kServiceDisappeared.code)) {
              return null;
            }
            return Future<vm_service.Isolate?>.error(error, stackTrace);
          },
        );
  }

  /// Attempt to retrieve the isolate pause event with id [isolateId], or `null` if it has
  /// been collected.
  Future<vm_service.Event?> getIsolatePauseEventOrNull(String isolateId) async {
    return service
        .getIsolatePauseEvent(isolateId)
        .then<vm_service.Event?>(
          (vm_service.Event event) => event,
          onError: (Object? error, StackTrace stackTrace) {
            if (error is vm_service.SentinelException ||
                error == null ||
                (error is vm_service.RPCError &&
                    error.code == vm_service.RPCErrorKind.kServiceDisappeared.code)) {
              return null;
            }
            return Future<vm_service.Event?>.error(error, stackTrace);
          },
        );
  }

  /// Create a new development file system on the device.
  Future<vm_service.Response> createDevFS(String fsName) {
    // Call the unchecked version of `callServiceExtension` because the caller
    // has custom handling of certain RPCErrors.
    return service.callServiceExtension('_createDevFS', args: <String, Object?>{'fsName': fsName});
  }

  /// Delete an existing file system.
  Future<void> deleteDevFS(String fsName) async {
    await _checkedCallServiceExtension('_deleteDevFS', args: <String, Object?>{'fsName': fsName});
  }

  Future<vm_service.Response?> screenshotSkp() {
    return _checkedCallServiceExtension(kScreenshotSkpMethod);
  }

  /// Set the VM timeline flags.
  Future<void> setTimelineFlags(List<String> recordedStreams) async {
    await _checkedCallServiceExtension(
      'setVMTimelineFlags',
      args: <String, Object?>{'recordedStreams': recordedStreams},
    );
  }

  Future<vm_service.Response?> getTimeline() {
    return _checkedCallServiceExtension('getVMTimeline');
  }

  Future<void> dispose() async {
    await service.dispose();
  }
}

/// Thrown when the VM Service disappears while calls are being made to it.
class VmServiceDisappearedException implements Exception {}

/// Thrown when the frontend service fails to compile an expression due to an
/// error.
class VmServiceExpressionCompilationException implements Exception {
  const VmServiceExpressionCompilationException(this.errorMessage);

  final String errorMessage;
}

/// Whether the event attached to an [vm_service.Isolate.pauseEvent] should be
/// considered a "pause" event.
bool isPauseEvent(String kind) {
  return kind == vm_service.EventKind.kPauseStart ||
      kind == vm_service.EventKind.kPauseExit ||
      kind == vm_service.EventKind.kPauseBreakpoint ||
      kind == vm_service.EventKind.kPauseInterrupted ||
      kind == vm_service.EventKind.kPauseException ||
      kind == vm_service.EventKind.kPausePostRequest ||
      kind == vm_service.EventKind.kNone;
}

/// A brightness enum that matches the values defined in
/// https://github.com/flutter/flutter/blob/230240c56880f2c19bf92d2c32203b064054f173/engine/src/flutter/lib/ui/window.dart#L1073
/// Describes the contrast of a theme or color palette.
enum Brightness {
  /// The color is dark and will require a light text color to achieve readable
  /// contrast.
  ///
  /// For example, the color might be dark grey, requiring white text.
  dark,

  /// The color is light and will require a dark text color to achieve readable
  /// contrast.
  ///
  /// For example, the color might be bright white, requiring black text.
  light,
}

/// Process a VM service log event into a string message.
///
/// Uses a permissive UTF-8 decoder because app-generated logs may contain
/// invalid UTF-8 from external sources (Bluetooth devices, network APIs, etc.).
String processVmServiceMessage(vm_service.Event event) {
  // Use permissive decoder for app logs that may have invalid UTF-8
  final String message = utf8AllowMalformed.decode(base64.decode(event.bytes!));
  // Remove extra trailing newlines appended by the vm service.
  if (message.endsWith('\n')) {
    return message.substring(0, message.length - 1);
  }
  return message;
}

extension RPCErrorExtension on vm_service.RPCError {
  bool get isConnectionDisposedException =>
      code == vm_service.RPCErrorKind.kServiceDisappeared.code ||
      code == vm_service.RPCErrorKind.kConnectionDisposed.code ||
      message.contains('Service connection disposed');

  /// DWDS throws an internal error (-32603) when a service extension is called
  /// but has not been registered yet, due to a null-assertion on the looked up method in JS.
  /// On native platforms, this throws `kMethodNotFound` (-32601).
  // TODO(kevmoo): Remove this work-around once https://github.com/dart-lang/sdk/issues/63424 is fixed.
  bool get isServiceExtensionUnregisteredError =>
      code == vm_service.RPCErrorKind.kMethodNotFound.code ||
      (code == vm_service.RPCErrorKind.kInternalError.code &&
          message.contains('Unexpected null value'));
}
