// Copyright (c) 2021, 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';
import 'dart:io';

import 'package:path/path.dart' as path;
import 'package:pedantic/pedantic.dart';

import '../logging.dart';
import '../protocol_common.dart';

/// A mixin providing some utility functions for locating/working with
/// package_config.json files.
mixin PackageConfigUtils {
  /// Find the `package_config.json` file for the program being launched.
  ///
  /// TODO(dantup): Remove this once
  ///   https://github.com/dart-lang/sdk/issues/45530 is done as it will not be
  ///   necessary.
  File? findPackageConfigFile(String possibleRoot) {
    File? packageConfig;
    while (true) {
      packageConfig =
          File(path.join(possibleRoot, '.dart_tool', 'package_config.json'));

      // If this packageconfig exists, use it.
      if (packageConfig.existsSync()) {
        break;
      }

      final parent = path.dirname(possibleRoot);

      // If we can't go up anymore, the search failed.
      if (parent == possibleRoot) {
        packageConfig = null;
        break;
      }

      possibleRoot = parent;
    }

    return packageConfig;
  }
}

/// A mixin for tracking additional PIDs that can be shut down at the end of a
/// debug session.
mixin PidTracker {
  /// Process IDs to terminate during shutdown.
  ///
  /// This may be populated with pids from the VM Service to ensure we clean up
  /// properly where signals may not be passed through the shell to the
  /// underlying VM process.
  /// https://github.com/Dart-Code/Dart-Code/issues/907
  final pidsToTerminate = <int>{};

  /// Terminates all processes with the PIDs registered in [pidsToTerminate].
  void terminatePids(ProcessSignal signal) {
    // TODO(dantup): In Dart-Code DAP, we first try again with sigint and wait
    // for a few seconds before sending sigkill.
    pidsToTerminate.forEach(
      (pid) => Process.killPid(pid, signal),
    );
  }
}

/// A mixin providing some utility functions for adapters that run tests and
/// provides some basic test reporting since otherwise nothing is printed when
/// using the JSON test reporter.
mixin TestAdapter {
  static const _tick = "✓";
  static const _cross = "✖";

  /// Test names by testID.
  ///
  /// Stored in testStart so that they can be looked up in testDone.
  Map<int, String> _testNames = {};

  void sendEvent(EventBody body, {String? eventType});
  void sendOutput(String category, String message);

  void sendTestEvents(Object testNotification) {
    // Send the JSON package as a raw notification so the client can interpret
    // the results (for example to populate a test tree).
    sendEvent(RawEventBody(testNotification),
        eventType: 'dart.testNotification');

    // Additionally, send a textual output so that the user also has visible
    // output in the Debug Console.
    if (testNotification is Map<String, Object?>) {
      sendTestTextOutput(testNotification);
    }
  }

  /// Sends textual output for tests, including pass/fail and test output.
  ///
  /// This is sent so that clients that do not handle the package:test JSON
  /// events still get some useful textual output in their Debug Consoles.
  void sendTestTextOutput(Map<String, Object?> testNotification) {
    switch (testNotification['type']) {
      case 'testStart':
        // When a test starts, capture its name by ID so we can get it back when
        // testDone comes.
        final test = testNotification['test'] as Map<String, Object?>?;
        if (test != null) {
          final testID = test['id'] as int?;
          final testName = test['name'] as String?;
          if (testID != null && testName != null) {
            _testNames[testID] = testName;
          }
        }
        break;

      case 'testDone':
        // Print the status of completed tests with a tick/cross.
        if (testNotification['hidden'] == true) {
          break;
        }
        final testID = testNotification['testID'] as int?;
        if (testID != null) {
          final testName = _testNames[testID];
          if (testName != null) {
            final symbol =
                testNotification['result'] == "success" ? _tick : _cross;
            sendOutput('console', '$symbol $testName\n');
          }
        }
        break;

      case 'print':
        final message = testNotification['message'] as String?;
        if (message != null) {
          sendOutput('stdout', '${message.trimRight()}\n');
        }
        break;

      case 'error':
        final error = testNotification['error'] as String?;
        final stack = testNotification['stackTrace'] as String?;
        if (error != null) {
          sendOutput('stderr', '${error.trimRight()}\n');
        }
        if (stack != null) {
          sendOutput('stderr', '${stack.trimRight()}\n');
        }
        break;
    }
  }
}

/// A mixin providing some utility functions for working with vm-service-info
/// files such as ensuring a temp folder exists to create them in, and waiting
/// for the file to become valid parsable JSON.
mixin VmServiceInfoFileUtils {
  /// Creates a temp folder for the VM to write the service-info-file into and
  /// returns the [File] to use.
  File generateVmServiceInfoFile() {
    // Using tmpDir.createTempory() is flakey on Windows+Linux (at least
    // on GitHub Actions) complaining the file does not exist when creating a
    // watcher. Creating/watching a folder and writing the file into it seems
    // to be reliable.
    final serviceInfoFilePath = path.join(
      Directory.systemTemp.createTempSync('dart-vm-service').path,
      'vm.json',
    );

    return File(serviceInfoFilePath);
  }

  /// Waits for [vmServiceInfoFile] to exist and become valid before returning
  /// the VM Service URI contained within.
  Future<Uri> waitForVmServiceInfoFile(
    Logger? logger,
    File vmServiceInfoFile,
  ) async {
    final completer = Completer<Uri>();
    late final StreamSubscription<FileSystemEvent> vmServiceInfoFileWatcher;

    Uri? tryParseServiceInfoFile(FileSystemEvent event) {
      final uri = _readVmServiceInfoFile(logger, vmServiceInfoFile);
      if (uri != null && !completer.isCompleted) {
        vmServiceInfoFileWatcher.cancel();
        completer.complete(uri);
      }
    }

    vmServiceInfoFileWatcher = vmServiceInfoFile.parent
        .watch(events: FileSystemEvent.all)
        .where((event) => event.path == vmServiceInfoFile.path)
        .listen(
          tryParseServiceInfoFile,
          onError: (e) => logger?.call('Ignoring exception from watcher: $e'),
        );

    // After setting up the watcher, also check if the file already exists to
    // ensure we don't miss it if it was created right before we set the
    // watched up.
    final uri = _readVmServiceInfoFile(logger, vmServiceInfoFile);
    if (uri != null && !completer.isCompleted) {
      unawaited(vmServiceInfoFileWatcher.cancel());
      completer.complete(uri);
    }

    return completer.future;
  }

  /// Attempts to read VM Service info from a watcher event.
  ///
  /// If successful, returns the URI. Otherwise, returns null.
  Uri? _readVmServiceInfoFile(Logger? logger, File file) {
    try {
      final content = file.readAsStringSync();
      final json = jsonDecode(content);
      return Uri.parse(json['uri']);
    } catch (e) {
      // It's possible we tried to read the file before it was completely
      // written so ignore and try again on the next event.
      logger?.call('Ignoring error parsing vm-service-info file: $e');
    }
  }
}
