// Copyright 2013 The Flutter Authors. 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:io' show Directory;

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

import '../dart_utils.dart';

import '../proc_utils.dart';
import '../worker_pool.dart';
import 'command.dart';
import 'flags.dart';

/// The different kind of linters we support.
enum Linter {
  /// Dart linter
  dart,

  /// Java linter
  java,

  /// C/C++ linter
  c,

  /// Python linter
  python
}

class _LinterDescription {
  _LinterDescription(this.linter, this.cwd, this.command);

  final Linter linter;
  final Directory cwd;
  final List<String> command;
}

/// The root 'lint' command.
final class LintCommand extends CommandBase {
  /// Constructs the 'lint' command.
  LintCommand({
    required super.environment,
    super.usageLineLength,
  }) {
    final String engineFlutterPath = environment.engine.flutterDir.path;
    _linters[Linter.dart] = _LinterDescription(
        Linter.dart, environment.engine.flutterDir, <String>[
      p.join(engineFlutterPath, 'ci', 'analyze.sh'),
      findDartBinDirectory(environment)
    ]);
    _linters[Linter.java] =
        _LinterDescription(Linter.java, environment.engine.flutterDir, <String>[
      findDartBinary(environment), '--disable-dart-dev',
      p.join(engineFlutterPath, 'tools', 'android_lint', 'bin', 'main.dart'),
    ]);
    _linters[Linter.c] = _LinterDescription(
        Linter.c,
        environment.engine.flutterDir,
        <String>[p.join(engineFlutterPath, 'ci', 'clang_tidy.sh')]);
    _linters[Linter.python] = _LinterDescription(
        Linter.python,
        environment.engine.flutterDir,
        <String>[p.join(engineFlutterPath, 'ci', 'pylint.sh')]);
    argParser.addFlag(
      quietFlag,
      abbr: 'q',
      help: 'Prints minimal output',
    );
  }

  final Map<Linter, _LinterDescription> _linters =
      <Linter, _LinterDescription>{};

  @override
  String get name => 'lint';

  @override
  String get description => 'Lint the engine repository.';

  @override
  Future<int> run() async {
    // TODO(loic-sharma): Relax this restriction.
    if (environment.platform.isWindows) {
      environment.logger
          .fatal('lint command is not supported on Windows (for now).');
    }
    final WorkerPool wp =
        WorkerPool(environment, ProcessTaskProgressReporter(environment));

    final Set<ProcessTask> tasks = <ProcessTask>{};
    for (final MapEntry<Linter, _LinterDescription> entry in _linters.entries) {
      tasks.add(ProcessTask(
          entry.key.name, environment, entry.value.cwd, entry.value.command));
    }
    final bool r = await wp.run(tasks);

    final bool quiet = argResults![quietFlag] as bool;
    if (!quiet) {
      environment.logger.status('\nDumping failure logs\n');
      for (final ProcessTask pt in tasks) {
        final ProcessArtifacts pa = pt.processArtifacts;
        if (pa.exitCode == 0) {
          continue;
        }
        environment.logger.status('Linter ${pt.name} found issues:');
        environment.logger.status('${pa.stdout}\n');
        environment.logger.status('${pa.stderr}\n');
      }
    }
    return r ? 0 : 1;
  }
}
