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

import 'repository.dart';
import 'utils.dart';

class FuchsiaEmulator {
  static final Uri toolsDir =
      Repository.uri.resolve('third_party/fuchsia/sdk/linux/tools/x64/');
  static final Uri scriptsDir =
      Repository.uri.resolve('third_party/fuchsia/sdk/linux/bin/');
  static final String femuTool = scriptsDir.resolve('femu.sh').toFilePath();
  static final String fserveTool = toolsDir.resolve('fserve').toFilePath();
  static final String fpubTool = toolsDir.resolve('fpublish').toFilePath();
  static final String fsshTool = toolsDir.resolve('fssh').toFilePath();
  static final RegExp emulatorReadyPattern =
      RegExp(r'Using unique host name (.+)\.local\.');
  static final RegExp emulatorPidPattern =
      RegExp(r'([0-9]+) .* qemu-system-x86');
  static final String serverReadyPattern = '[pm serve] serving';

  static FuchsiaEmulator? _inst;

  Process? _emu;
  Process? _server;
  late String _deviceName;

  static Future<void> publishPackage(String buildDir, String mode) async {
    if (_inst == null) {
      _inst = FuchsiaEmulator();
      await _inst!._start();
    }
    await _inst!._publishPackage(buildDir, mode);
  }

  static void stop() {
    _inst?._stop();
  }

  static List<String> getTestArgs(String mode, List<String> arguments) {
    return _inst!._getSshArgs(
        mode,
        arguments.map((arg) =>
            arg.replaceAll(Repository.uri.toFilePath(), '/pkg/data/')));
  }

  Future<void> _start() async {
    // Start the emulator.
    DebugLogger.info('Starting Fuchsia emulator');
    _emu = await Process.start(
        'xvfb-run', [femuTool, '--image', 'qemu-x64', '-N', '--headless']);

    // Wait until the emulator is ready and has a valid device name.
    var deviceNameFuture = Completer<String>();
    var emuStdout = StringBuffer();
    var emuStderr = StringBuffer();
    _emu!.stdout.transform(utf8.decoder).transform(const LineSplitter()).listen(
        (String line) {
      if (!deviceNameFuture.isCompleted) {
        emuStdout.write(line);
        emuStdout.write('\n');
        var match = emulatorReadyPattern.firstMatch(line);
        if (match != null) {
          deviceNameFuture.complete(match.group(1));
        }
      }
    }, onDone: () {
      if (!deviceNameFuture.isCompleted) {
        deviceNameFuture.completeError(
            'Fuchsia emulator terminated unexpectedly.\n\n' +
                _formatOutputs(emuStdout.toString(), emuStderr.toString()));
      }
      _stop();
    });
    _emu!.stderr
        .transform(utf8.decoder)
        .transform(const LineSplitter())
        .listen((String line) {
      if (!deviceNameFuture.isCompleted) {
        emuStderr.write(line);
        emuStderr.write('\n');
      }
    });
    _deviceName = await deviceNameFuture.future;
    DebugLogger.info('Fuchsia emulator ready: $_deviceName');

    // Start the server.
    DebugLogger.info('Starting Fuchsia package server');
    _server = await Process.start(fserveTool, [
      '--bucket',
      'fuchsia-sdk',
      '--image',
      'qemu-x64',
      '--device-name',
      _deviceName
    ]);

    // Wait until the server is ready to serve packages.
    var serverReadyFuture = Completer<void>();
    var serverStdout = StringBuffer();
    var serverStderr = StringBuffer();
    _server!.stdout
        .transform(utf8.decoder)
        .transform(const LineSplitter())
        .listen((String line) {
      if (!serverReadyFuture.isCompleted) {
        serverStdout.write(line);
        serverStdout.write('\n');
        if (line.contains(serverReadyPattern)) {
          serverReadyFuture.complete();
        }
      }
    }, onDone: () {
      if (!serverReadyFuture.isCompleted) {
        serverReadyFuture.completeError(
            'Fuchsia package server terminated unexpectedly.\n\n' +
                _formatOutputs(
                    serverStdout.toString(), serverStderr.toString()));
      }
      _stop();
    });
    _server!.stderr
        .transform(utf8.decoder)
        .transform(const LineSplitter())
        .listen((String line) {
      if (!serverReadyFuture.isCompleted) {
        serverStderr.write(line);
        serverStderr.write('\n');
      }
    });
    await serverReadyFuture.future;
    DebugLogger.info('Fuchsia package server ready');
  }

  List<String> _getSshArgs(String mode, Iterable<String> args) {
    var sshArgs = [
      '--device-name',
      _deviceName,
      'run',
      'fuchsia-pkg://fuchsia.com/dart_test_$mode#meta/dart.cmx'
    ];
    return sshArgs..addAll(args);
  }

  Future<void> _publishPackage(String buildDir, String mode) async {
    var packageFile = '$buildDir/gen/dart_test_$mode/dart_test_$mode.far';
    if (!File(packageFile).existsSync()) {
      throw 'File $packageFile does not exist. Please build fuchsia_test_package.';
    }
    DebugLogger.info('Publishing package: $packageFile');
    var result = await Process.run(fpubTool, [packageFile]);
    if (result.exitCode != 0) {
      _stop();
      throw _formatFailedResult('Publishing package', result);
    }

    // Verify that the publication was successful by running hello_test.dart.
    // This also forces the emulator to download the published package from the
    // server, rather than waiting until the first tests are run. It can take a
    // minute or two to transfer, and we don't want to eat into the timeout
    // timer of the first tests.
    DebugLogger.info('Verifying publication');
    result = await Process.run(fsshTool,
        _getSshArgs(mode, ['/pkg/data/pkg/testing/test/hello_test.dart']));
    if (result.exitCode != 0 || result.stdout != 'Hello, World!\n') {
      _stop();
      throw _formatFailedResult('Verifying publication', result);
    }
    DebugLogger.info('Publication successful');
  }

  void _stop() {
    if (_emu != null) {
      DebugLogger.info('Stopping Fuchsia emulator');
      _emu!.kill(ProcessSignal.sigint);
      _emu = null;

      // Killing femu.sh seems to leave the underlying emulator running. So
      // manually find the process and terminate it by PID.
      var result = Process.runSync('ps', []);
      var emuPid = int.tryParse(
          emulatorPidPattern.firstMatch(result.stdout as String)?.group(1) ??
              "");
      if (result.exitCode != 0 || emuPid == null) {
        DebugLogger.info(
            _formatFailedResult('Searching for emulator process', result));
      } else {
        Process.killPid(emuPid);
        DebugLogger.info('Fuchsia emulator stopped');
      }
    }

    if (_server != null) {
      DebugLogger.info('Stopping Fuchsia package server');
      _server!.kill();
      _server = null;

      // fserve.sh starts a package manager process in the background. We need
      // to manually kill this process, using fserve.sh again.
      var result = Process.runSync(fserveTool, ['--kill']);
      if (result.exitCode != 0) {
        DebugLogger.info(
            _formatFailedResult('Killing package manager', result));
      } else {
        DebugLogger.info('Fuchsia package server stopped');
      }
    }
  }

  String _formatOutputs(String stdout, String stderr) {
    var output = "";
    if (stdout.isNotEmpty) output += "=== STDOUT ===\n$stdout\n";
    if (stderr.isNotEmpty) output += "=== STDERR ===\n$stderr\n";
    return output;
  }

  String _formatFailedResult(String name, ProcessResult result) {
    return '$name failed with exit code: ${result.exitCode}\n\n' +
        _formatOutputs(result.stdout as String, result.stderr as String);
  }
}
