// Copyright 2014 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.

// @dart = 2.8

import 'package:args/args.dart';
import 'package:meta/meta.dart';
import 'package:process/process.dart';

import '../artifacts.dart';
import '../base/common.dart';
import '../base/file_system.dart';
import '../base/io.dart';
import '../base/logger.dart';
import '../base/platform.dart';
import '../base/terminal.dart';
import '../dart/analysis.dart';
import 'analyze_base.dart';

class AnalyzeContinuously extends AnalyzeBase {
  AnalyzeContinuously(
    ArgResults argResults,
    List<String> repoRoots,
    List<Directory> repoPackages, {
    @required FileSystem fileSystem,
    @required Logger logger,
    @required Terminal terminal,
    @required Platform platform,
    @required ProcessManager processManager,
    @required Artifacts artifacts,
  }) : super(
        argResults,
        repoPackages: repoPackages,
        repoRoots: repoRoots,
        fileSystem: fileSystem,
        logger: logger,
        platform: platform,
        terminal: terminal,
        processManager: processManager,
        artifacts: artifacts,
      );

  String analysisTarget;
  bool firstAnalysis = true;
  Set<String> analyzedPaths = <String>{};
  Map<String, List<AnalysisError>> analysisErrors = <String, List<AnalysisError>>{};
  Stopwatch analysisTimer;
  int lastErrorCount = 0;
  Status analysisStatus;

  @override
  Future<void> analyze() async {
    List<String> directories;

    if (isFlutterRepo) {
      final PackageDependencyTracker dependencies = PackageDependencyTracker();
      dependencies.checkForConflictingDependencies(repoPackages, dependencies);

      directories = repoRoots;
      analysisTarget = 'Flutter repository';

      logger.printTrace('Analyzing Flutter repository:');
      for (final String projectPath in repoRoots) {
        logger.printTrace('  ${fileSystem.path.relative(projectPath)}');
      }
    } else {
      directories = <String>[fileSystem.currentDirectory.path];
      analysisTarget = fileSystem.currentDirectory.path;
    }

    final AnalysisServer server = AnalysisServer(
      sdkPath,
      directories,
      fileSystem: fileSystem,
      logger: logger,
      platform: platform,
      processManager: processManager,
      terminal: terminal,
      protocolTrafficLog: protocolTrafficLog,
    );
    server.onAnalyzing.listen((bool isAnalyzing) => _handleAnalysisStatus(server, isAnalyzing));
    server.onErrors.listen(_handleAnalysisErrors);

    await server.start();
    final int exitCode = await server.onExit;

    final String message = 'Analysis server exited with code $exitCode.';
    if (exitCode != 0) {
      throwToolExit(message, exitCode: exitCode);
    }
    logger.printStatus(message);

    if (server.didServerErrorOccur) {
      throwToolExit('Server error(s) occurred.');
    }
  }

  void _handleAnalysisStatus(AnalysisServer server, bool isAnalyzing) {
    if (isAnalyzing) {
      analysisStatus?.cancel();
      if (!firstAnalysis) {
        logger.printStatus('\n');
      }
      analysisStatus = logger.startProgress('Analyzing $analysisTarget...');
      analyzedPaths.clear();
      analysisTimer = Stopwatch()..start();
    } else {
      analysisStatus?.stop();
      analysisStatus = null;
      analysisTimer.stop();

      logger.printStatus(terminal.clearScreen(), newline: false);

      // Remove errors for deleted files, sort, and print errors.
      final List<AnalysisError> errors = <AnalysisError>[];
      for (final String path in analysisErrors.keys.toList()) {
        if (fileSystem.isFileSync(path)) {
          errors.addAll(analysisErrors[path]);
        } else {
          analysisErrors.remove(path);
        }
      }

      errors.sort();

      for (final AnalysisError error in errors) {
        logger.printStatus(error.toString());
        if (error.code != null) {
          logger.printTrace('error code: ${error.code}');
        }
      }

      dumpErrors(errors.map<String>((AnalysisError error) => error.toLegacyString()));

      final int issueCount = errors.length;
      final int issueDiff = issueCount - lastErrorCount;
      lastErrorCount = issueCount;
      final String seconds = (analysisTimer.elapsedMilliseconds / 1000.0).toStringAsFixed(2);
      final String errorsMessage = AnalyzeBase.generateErrorsMessage(
        issueCount: issueCount,
        issueDiff: issueDiff,
        files: analyzedPaths.length,
        seconds: seconds,
      );

      logger.printStatus(errorsMessage);

      if (firstAnalysis && isBenchmarking) {
        writeBenchmark(analysisTimer, issueCount);
        server.dispose().whenComplete(() { exit(issueCount > 0 ? 1 : 0); });
      }

      firstAnalysis = false;
    }
  }

  void _handleAnalysisErrors(FileAnalysisErrors fileErrors) {
    fileErrors.errors.removeWhere((AnalysisError error) => error.type == 'TODO');

    analyzedPaths.add(fileErrors.file);
    analysisErrors[fileErrors.file] = fileErrors.errors;
  }
}
