// 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:dartdev/src/commands/create.dart';
import 'package:dartdev/src/templates.dart';
import 'package:path/path.dart' as path;
import 'package:test/test.dart';

import '../utils.dart';

void main() {
  group('create integration', defineCreateTests, timeout: longTimeout);
}

void defineCreateTests() {
  TestProject p;

  setUp(() => p = null);

  tearDown(() async => await p?.dispose());

  // Create tests for each template.
  for (String templateId in CreateCommand.legalTemplateIds) {
    test(templateId, () async {
      const projectName = 'template_project';
      p = project();
      final templateGenerator = getGenerator(templateId);

      ProcessResult createResult = await p.run([
        'create',
        '--force',
        '--template',
        templateId,
        projectName,
      ]);
      expect(createResult.exitCode, 0, reason: createResult.stderr);

      // Validate that the project analyzes cleanly.
      ProcessResult analyzeResult =
          await p.run(['analyze', '--fatal-infos', projectName]);
      expect(analyzeResult.exitCode, 0, reason: analyzeResult.stdout);

      // Validate that the code is well formatted.
      ProcessResult formatResult = await p.run([
        'format',
        '--output',
        'none',
        '--set-exit-if-changed',
        projectName,
      ]);
      expect(formatResult.exitCode, 0, reason: formatResult.stdout);

      // Process the execution instructions provided by the template.
      final runCommands = templateGenerator
          .getInstallInstructions(
            projectName,
            projectName,
          )
          .split('\n')
          // Remove directory change instructions.
          .sublist(1)
          .map((command) => command.trim())
          .map((command) {
        final commandParts = command.split(' ');
        if (command.startsWith('dart ')) {
          return commandParts.sublist(1);
        }
        return commandParts;
      }).toList();

      final isServerTemplate = templateGenerator.categories.contains('server');
      final isWebTemplate = templateGenerator.categories.contains('web');
      final workingDir = path.join(p.dirPath, projectName);

      // Execute the templates run instructions.
      for (int i = 0; i < runCommands.length; ++i) {
        // The last command is always the command to execute the code generated
        // by the template.
        final isLastCommand = i == runCommands.length - 1;
        final command = runCommands[i];
        Process process;

        if (isLastCommand && isWebTemplate) {
          // The web template uses `webdev` to execute, not `dart`, so don't
          // run the test through the project utility method.
          process = await Process.start(
            path.join(
              p.pubCacheBinPath,
              Platform.isWindows ? '${command.first}.bat' : command.first,
            ),
            command.sublist(1),
            workingDirectory: workingDir,
          );
        } else {
          process = await p.start(
            command,
            workingDir: workingDir,
          );
        }

        if (isLastCommand && (isServerTemplate || isWebTemplate)) {
          final completer = Completer<void>();
          StreamSubscription sub;
          // Listen for well-known output from specific templates to determine
          // if they've executed correctly. These templates won't exit on their
          // own, so we'll need to terminate the process once we've verified it
          // runs correctly.
          sub = process.stdout.transform(utf8.decoder).listen((e) {
            if ((isServerTemplate && e.contains('Server listening on port')) ||
                (isWebTemplate && e.contains('Succeeded after'))) {
              sub.cancel();
              process.kill();
              completer.complete();
            }
          });
          await completer.future;

          // Since we had to terminate the process manually, we aren't certain
          // as to what the exit code will be on all platforms (should be -15
          // for POSIX systems), so we'll just wait for the process to exit
          // here.
          await process.exitCode;
        } else {
          // If the sample should exit on its own, it should always result in
          // an exit code of 0.
          expect(await process.exitCode, 0);
        }
      }
    });
  }
}
