// Copyright (c) 2020, the Dart project authors.  Please see the AUTHORS file
// for details. 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:convert' show base64Decode, base64Encode;

import 'package:json_rpc_2/json_rpc_2.dart' as json_rpc;
import 'package:vm_service/vm_service.dart';

import 'client.dart';
import 'constants.dart';
import 'dds_impl.dart';
import 'utils/mutex.dart';

/// This file contains functionality used to track the running state of
/// all isolates in a given Dart process.
///
/// [_RunningIsolate] is a representation of a single live isolate and contains
/// running state information for that isolate. In addition, approvals from
/// clients used to synchronize isolate resuming across multiple clients are
/// tracked in this class.
///
/// The [IsolateManager] keeps track of all the isolates in the
/// target process and handles isolate lifecycle events including:
///   - Startup
///   - Shutdown
///   - Pauses
///
/// The [IsolateManager] also handles the `resume` RPC, which checks the
/// resume approvals in the target [_RunningIsolate] to determine if the
/// isolate should be resumed or wait for additional approvals to be granted.

enum _IsolateState {
  start,
  running,
  pauseStart,
  pauseExit,
  pausePostRequest,
  unknown,
}

class RunningIsolate {
  RunningIsolate(this.isolateManager, this.id, this.name)
      : _state = _IsolateState.unknown;

  // State setters.
  void pausedOnExit() => _state = _IsolateState.pauseExit;

  void pausedOnStart() => _state = _IsolateState.pauseStart;

  void pausedPostRequest() => _state = _IsolateState.pausePostRequest;

  void resumed() => running();

  void running() => _state = _IsolateState.running;

  void started() => _state = _IsolateState.start;

  /// Resumes the isolate if all clients which need to approve a resume have
  /// done so. Called when the last client of a given name disconnects or
  /// changes name to ensure we don't deadlock waiting for approval to resume
  /// from a disconnected client.
  Future<void> maybeResumeAfterClientChange(String? clientName) async {
    // Remove approvals from the disconnected client.
    _resumeApprovalsByName.remove(clientName);

    if (shouldResume()) {
      clearResumeApprovals();
      await isolateManager.dds.vmServiceClient.sendRequest('resume', {
        'isolateId': id,
      });
    }
  }

  /// Returns true if this isolate should resume given its client approvals
  /// state.
  ///
  /// If `resumingClient` is provided, it will be added to the set of clients
  /// which have provided approval to resume this isolate. If not provided,
  /// the existing approvals state will be examined to see if the isolate
  /// should resume due to a client disconnect or name change.
  bool shouldResume({DartDevelopmentServiceClient? resumingClient}) {
    if (resumingClient != null) {
      // Mark approval by the client.
      _resumeApprovalsByName.add(resumingClient.name);
    }

    // If the user is required to resume the isolate, we won't resume until a
    // `resume` request is received or `setRequireUserPermissionToResume` is
    // invoked and removes the requirement for this pause type.
    final userPermissionMask =
        isolateManager._requireUserPermissionToResumeMask;
    if (userPermissionMask & _isolateStateMask != 0) {
      return false;
    }

    final requiredClientApprovals = <String>{};
    final permissions =
        isolateManager.dds.clientManager.clientResumePermissions;

    // Determine which clients require approval for this pause type.
    permissions.forEach((clientName, clientNamePermissions) {
      if (clientNamePermissions.permissionsMask & _isolateStateMask != 0) {
        requiredClientApprovals.add(clientName!);
      }
    });

    // We require at least a single client to resume, even if that client
    // doesn't require resume approval.
    if (_resumeApprovalsByName.isEmpty) {
      return false;
    }
    // If all the required approvals are present, we should resume.
    return _resumeApprovalsByName.containsAll(requiredClientApprovals);
  }

  /// Resets the internal resume approvals state.
  ///
  /// Should always be called after an isolate is resumed.
  void clearResumeApprovals() => _resumeApprovalsByName.clear();

  int get _isolateStateMask => isolateStateToMaskMapping[_state] ?? 0;

  static const isolateStateToMaskMapping = {
    _IsolateState.pauseStart: PauseTypeMasks.pauseOnStartMask,
    _IsolateState.pausePostRequest: PauseTypeMasks.pauseOnReloadMask,
    _IsolateState.pauseExit: PauseTypeMasks.pauseOnExitMask,
  };

  final IsolateManager isolateManager;
  final String name;
  final String id;
  final Set<String?> _resumeApprovalsByName = {};
  _IsolateState _state;
}

class IsolateManager {
  IsolateManager(this.dds);

  /// Handles state changes for isolates.
  void handleIsolateEvent(Event event) {
    // There's no interesting information about isolate state associated with
    // IsolateSpawn or IsolateReload events.
    // TODO(bkonyi): why isn't IsolateSpawn in package:vm_service
    if (event.kind! == ServiceEvents.isolateSpawn ||
        event.kind == EventKind.kIsolateReload) {
      return;
    }

    final isolateData = event.isolate!;
    final id = isolateData.id!;
    final name = isolateData.name!;
    _updateIsolateState(id, name, event.kind!);
  }

  void _updateIsolateState(String id, String name, String eventKind) {
    _mutex.runGuarded(
      () {
        switch (eventKind) {
          case ServiceEvents.isolateStart:
            isolateStarted(id, name);
            break;
          case ServiceEvents.isolateExit:
            isolateExited(id);
            break;
          default:
            final isolate = isolates[id];
            // The isolate may have disappeared after the state event was sent.
            if (isolate == null) {
              return;
            }
            switch (eventKind) {
              case ServiceEvents.pauseExit:
                isolate.pausedOnExit();
                break;
              case ServiceEvents.pausePostRequest:
                isolate.pausedPostRequest();
                break;
              case ServiceEvents.pauseStart:
                isolate.pausedOnStart();
                break;
              case ServiceEvents.resume:
                isolate.resumed();
                break;
              default:
                break;
            }
        }
      },
    );
  }

  /// Initializes the set of running isolates.
  Future<void> initialize() async {
    if (_initialized) {
      return;
    }
    final vm = await dds.vmServiceClient.sendRequest('getVM');
    final isolateRefs = vm['isolates'].cast<Map<String, dynamic>>();
    // Check the pause event for each isolate to determine whether or not the
    // isolate is already paused.
    for (final isolateRef in isolateRefs) {
      final id = isolateRef['id'];
      final name = isolateRef['name'];

      // Create an entry for the running isolate.
      initializeRunningIsolate(id, name);

      // The calls to `getIsolate` are intentionally unawaited as it's
      // possible for the isolate to be in a state where it is unable to
      // process service messages, potentially indefinitely. For example,
      // an isolate that invoked FFI code will be blocked until control is
      // returned from native code.
      //
      // See b/323386606 for details.
      unawaited(
        dds.vmServiceClient.sendRequest('getIsolate', {
          'isolateId': id,
        }).then(
          (isolate) async => await _mutex.runGuarded(
            () {
              // If the isolate has shutdown after the getVM request, ignore it and
              // continue to the next isolate.
              if (isolate['type'] == 'Sentinel') {
                return;
              }
              if (isolate.containsKey('pauseEvent')) {
                isolates[id] = RunningIsolate(this, id, name);
                final eventKind = isolate['pauseEvent']['kind'];
                _updateIsolateState(id, name, eventKind);
              } else {
                // If the isolate doesn't have a pauseEvent, assume it's running.
                isolateStarted(id, name);
              }
            },
          ),
        ),
      );
    }
    await _determineRequireUserPermissionToResumeFromFlags();
    _initialized = true;
  }

  /// This method creates an entry for a running isolate, leaves its run state
  /// as [_IsolateState.unknown].
  RunningIsolate initializeRunningIsolate(String id, String name) =>
      isolates.putIfAbsent(
        id,
        () => RunningIsolate(this, id, name),
      );

  /// Initializes state for a newly started isolate.
  void isolateStarted(String id, String name) {
    final isolate = initializeRunningIsolate(id, name);
    isolate.running();
    isolates[id] = isolate;
  }

  /// Cleans up state for an isolate that has exited.
  void isolateExited(String id) {
    isolates.remove(id);
  }

  /// Handles `resume` RPC requests.
  ///
  /// Invocations of `resume` are treated as user initiated and will bypass any
  /// resume permissions set by tooling, force resuming the isolate and clear
  /// any resume approvals.
  ///
  /// Returns a collected sentinel if the isolate no longer exists.
  Future<Map<String, dynamic>> resumeIsolate(
    DartDevelopmentServiceClient client,
    json_rpc.Parameters parameters,
  ) async {
    return await _mutex.runGuarded(
      () async {
        final isolateId = parameters['isolateId'].asString;
        final isolate = isolates[isolateId];
        if (isolate == null) {
          return RPCResponses.collectedSentinel;
        }
        return await _resumeCommon(isolate, parameters);
      },
    );
  }

  /// Handles `readyToResume` RPC requests. If the client requires
  /// that approval be given before resuming an isolate, this method will:
  ///
  ///   - Update the approval state for the isolate.
  ///   - Resume the isolate if approval has been given by all clients which
  ///     require approval.
  ///
  /// Returns a collected sentinel if the isolate no longer exists.
  Future<Map<String, dynamic>> readyToResume(
    DartDevelopmentServiceClient client,
    json_rpc.Parameters parameters,
  ) async {
    return await _mutex.runGuarded(
      () async {
        final isolateId = parameters['isolateId'].asString;
        final isolate = isolates[isolateId];
        if (isolate == null) {
          return RPCResponses.collectedSentinel;
        }
        if (isolate.shouldResume(resumingClient: client)) {
          return await _resumeCommon(isolate, parameters);
        }
        return RPCResponses.success;
      },
    );
  }

  Future<void> maybeResumeIsolates() async {
    await _mutex.runGuarded(() async {
      for (final isolate in isolates.values) {
        if (isolate.shouldResume()) {
          await _resumeCommon(isolate, json_rpc.Parameters('', {}));
        }
      }
    });
  }

  Future<Map<String, dynamic>> _resumeCommon(
    RunningIsolate isolate,
    json_rpc.Parameters parameters,
  ) async {
    isolate.clearResumeApprovals();
    return await _sendResumeRequest(isolate.id, parameters);
  }

  /// Handles `requireUserPermissionToResume` requests.
  ///
  /// Notifies DDS if it should wait for a `resume` request to resume isolates
  /// paused on start or exit.
  ///
  /// This RPC should only be invoked by tooling which launched the target Dart
  /// process and knows if the user indicated they wanted isolates paused on
  /// start or exit.
  Future<Map<String, dynamic>> requireUserPermissionToResume(
    DartDevelopmentServiceClient client,
    json_rpc.Parameters parameters,
  ) async {
    _setRequireUserPermissionToResume(
      onPauseStart: parameters['onPauseStart'].asBoolOr(false),
      onPauseExit: parameters['onPauseExit'].asBoolOr(false),
    );

    // Check if isolates have been waiting for a user resume and resume any
    // isolates that no longer need to wait for a user resume.
    await maybeResumeIsolates();

    return RPCResponses.success;
  }

  /// Handles `getRequireUserPermissionToResume` requests.
  ///
  /// Returns an object indicating whether or not a `resume` request is
  /// required for DDS to resume an isolate paused on start or exit.
  Future<Map<String, dynamic>> getRequireUserPermissionToResume(
      DartDevelopmentServiceClient client,
      json_rpc.Parameters parameters) async {
    bool flagFromMask(int mask) =>
        _requireUserPermissionToResumeMask & mask != 0;
    return <String, dynamic>{
      'type': 'ResumePermissionsRequired',
      'onPauseStart': flagFromMask(PauseTypeMasks.pauseOnStartMask),
      'onPauseExit': flagFromMask(PauseTypeMasks.pauseOnExitMask),
    };
  }

  Future<void> _determineRequireUserPermissionToResumeFromFlags() async {
    try {
      final result = await dds.vmServiceClient.sendRequest('getFlagList')
          as Map<String, dynamic>;
      final flagList = FlagList.parse(result);
      final flags = flagList!.flags!;

      bool? pauseOnStartValue;
      bool? pauseOnExitValue;
      for (final flag in flags) {
        if (flag.name == 'pause_isolates_on_start') {
          pauseOnStartValue = flag.valueAsString == 'true';
        }
        if (flag.name == 'pause_isolates_on_exit') {
          pauseOnExitValue = flag.valueAsString == 'true';
        }
        if (pauseOnStartValue != null && pauseOnExitValue != null) {
          break;
        }
      }

      _setRequireUserPermissionToResume(
        onPauseStart: pauseOnStartValue ?? false,
        onPauseExit: pauseOnExitValue ?? false,
      );
    } catch (_) {
      // Swallow any errors. Otherwise, this will cause initialization to
      // silently fail.
    }
  }

  void _setRequireUserPermissionToResume({
    required bool onPauseStart,
    required bool onPauseExit,
  }) {
    int pauseTypeMask = 0;
    if (onPauseStart) {
      pauseTypeMask |= PauseTypeMasks.pauseOnStartMask;
    }
    if (onPauseExit) {
      pauseTypeMask |= PauseTypeMasks.pauseOnExitMask;
    }
    _requireUserPermissionToResumeMask = pauseTypeMask;
  }

  Future<Map<String, dynamic>> getPerfettoVMTimelineWithCpuSamples(
      json_rpc.Parameters parameters) async {
    final timeOriginMicros = parameters['timeOriginMicros'].asIntOr(-1);
    final timeExtentMicros = parameters['timeExtentMicros'].asIntOr(-1);

    final timelineResult = await dds.vmServiceClient.sendRequest(
        'getPerfettoVMTimeline', {
      'timeOriginMicros': timeOriginMicros,
      'timeExtentMicros': timeExtentMicros
    });

    final combinedBytes = base64Decode(timelineResult['trace']).toList();

    for (final isolateId in isolates.keys) {
      try {
        final samplesResult =
            await dds.vmServiceClient.sendRequest('getPerfettoCpuSamples', {
          'isolateId': isolateId,
          'timeOriginMicros': timeOriginMicros,
          'timeExtentMicros': timeExtentMicros
        });
        combinedBytes.addAll(base64Decode(samplesResult['samples']));
      } on json_rpc.RpcException {
        // The isolate may not yet be runnable.
      }
    }
    timelineResult['trace'] = base64Encode(combinedBytes);
    return timelineResult;
  }

  /// Forwards a `resume` request to the VM service.
  Future<Map<String, dynamic>> _sendResumeRequest(
    String isolateId,
    json_rpc.Parameters parameters,
  ) async {
    const invalidFrameIndex = -1;
    final step = parameters['step'].asStringOr('');
    final frameIndex = parameters['frameIndex'].asIntOr(invalidFrameIndex);
    final resumeResult = await dds.vmServiceClient.sendRequest('resume', {
      'isolateId': isolateId,
      if (step.isNotEmpty) 'step': step,
      if (frameIndex != invalidFrameIndex) 'frameIndex': frameIndex,
    });
    return resumeResult;
  }

  bool _initialized = false;
  final DartDevelopmentServiceImpl dds;
  final _mutex = Mutex();
  int _requireUserPermissionToResumeMask = 0;
  final isolates = <String, RunningIsolate>{};
}
