// Copyright (c) 2019, 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:args/args.dart';
import 'package:args/command_runner.dart';
import 'package:async/async.dart';
import 'package:logging/logging.dart';

import '../daemon/app_domain.dart';
import '../daemon/daemon.dart';
import '../daemon/daemon_domain.dart';
import '../logging.dart';
import '../pubspec.dart';
import '../serve/dev_workflow.dart';
import '../serve/utils.dart';
import 'configuration.dart';
import 'shared.dart';

Stream<Map<String, dynamic>> get _stdinCommandStream => stdin
    .transform<String>(utf8.decoder)
    .transform<String>(const LineSplitter())
    .where((String line) => line.startsWith('[{') && line.endsWith('}]'))
    .map<Map<String, dynamic>>((String line) {
      line = line.substring(1, line.length - 1);
      return json.decode(line) as Map<String, dynamic>;
    });

void _stdoutCommandResponse(Map<String, dynamic> command) {
  stdout.writeln('[${json.encode(command)}]');
}

/// A mode for running WebDev from command-line tools.
///
/// Communication happens over STDIO using JSON-RPC.
///
/// This supports a subset of:
/// https://github.com/flutter/flutter/blob/master/packages/flutter_tools/doc/daemon.md
class DaemonCommand extends Command<int> {
  @override
  final name = 'daemon';

  @override
  final hidden = true;

  @override
  String get description =>
      'A mode for running WebDev from command-line tools.';

  @override
  final argParser = ArgParser()
    ..addMultiOption('launch-app', help: 'The html file to launch in chrome.');

  DaemonCommand() {
    addSharedArgs(argParser, releaseDefault: false);
  }

  @override
  Future<int> run() async {
    final configuration = Configuration.fromArgs(
      argResults,
      defaultConfiguration: Configuration(
        launchInChrome: true,
        debug: true,
        autoRun: false,
        release: false,
      ),
    );
    configureLogWriter(configuration.verbose);
    // Validate the pubspec first to ensure we are in a Dart project.
    try {
      await validatePubspecLock(configuration);
    } on PackageException catch (e) {
      logWriter(Level.SEVERE, 'Pubspec errors: ', error: '${e.details}');
      rethrow;
    }

    Daemon? daemon;
    DevWorkflow? workflow;
    var cancelCount = 0;
    final cancelSub =
        StreamGroup.merge([
          ProcessSignal.sigint.watch(),
          // SIGTERM is not supported on Windows.
          Platform.isWindows
              ? const Stream.empty()
              : ProcessSignal.sigterm.watch(),
        ]).listen((signal) async {
          cancelCount++;
          daemon?.shutdown();
          if (cancelCount > 1) exit(1);
        });
    try {
      daemon = Daemon(_stdinCommandStream, _stdoutCommandResponse);
      final daemonDomain = DaemonDomain(daemon);
      configureLogWriter(
        configuration.verbose,
        customLogWriter:
            (level, message, {loggerName, error, stackTrace, verbose}) {
              if (configuration.verbose || level >= Level.INFO) {
                daemonDomain.sendEvent('daemon.log', {
                  'log': formatLog(
                    level,
                    message,
                    loggerName: loggerName,
                    error: error,
                    stackTrace: stackTrace,
                  ),
                });
              }
            },
      );
      daemon.registerDomain(daemonDomain);
      final buildOptions = buildRunnerArgs(configuration);
      final extraArgs = argResults?.rest ?? [];
      final directoryArgs = extraArgs
          .where((arg) => !arg.startsWith('-'))
          .toList();
      final targetPorts = parseDirectoryArgs(
        directoryArgs,
        basePort: await findUnusedPort(),
      );
      validateLaunchApps(configuration.launchApps, targetPorts.keys);

      workflow = await DevWorkflow.start(
        configuration,
        buildOptions,
        targetPorts,
      );
      daemon.registerDomain(AppDomain(daemon, workflow.serverManager));
      await daemon.onExit;
      exitCode = 0;
      return 0;
    } catch (e) {
      daemon?.shutdown();
      exitCode = 1;
      rethrow;
    } finally {
      await workflow?.shutDown();
      // Only cancel this subscription after all shutdown work has completed.
      // https://github.com/dart-lang/sdk/issues/23074.
      await cancelSub.cancel();
      // For some reason Windows remains open due to what appears to be an
      // undrained `stdin`. Feel free to waste some time trying to remove this.
      if (Platform.isWindows) exit(exitCode);
    }
  }
}
