// Copyright (c) 2018, 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:build/build.dart';
import 'package:logging/logging.dart';
import 'package:path/path.dart' as p;

import '../asset_graph/node.dart';
import '../util/constants.dart';

/// A tracker for the errors which have already been reported during the current
/// build.
///
/// Errors that occur due to actions that are run within this build will be
/// reported directly as they happen. When an action is skipped and remains a
/// failure the error will not have been reported by the time we check wether
/// the build is failed.
///
/// The lifetime of this class should be a single build.
class FailureReporter {
  /// Removes all stored errors from previous builds.
  ///
  /// This should be called any time the build phases change since the naming
  /// scheme is dependent on the build phases.
  static Future<void> cleanErrorCache() async {
    final errorCacheDirectory = Directory(p.fromUri(errorCachePath));
    if (await errorCacheDirectory.exists()) {
      await errorCacheDirectory.delete(recursive: true);
    }
  }

  /// Remove the stored error for [phaseNumber] runnon on [primaryInput].
  ///
  /// This should be called anytime the action is being run.
  static Future<void> clean(int phaseNumber, AssetId primaryInput) async {
    final errorFile =
        File(_errorPathForPrimaryInput(phaseNumber, primaryInput));
    if (await errorFile.exists()) {
      await errorFile.delete();
    }
  }

  /// A set of Strings which uniquely identify a particular build action and
  /// it's primary input.
  final _reportedActions = <String>{};

  /// Indicate that a failure reason for the build step which would produce
  /// [output] and all other outputs from the same build step has been printed.
  Future<void> markReported(String actionDescription, GeneratedAssetNode output,
      Iterable<ErrorReport> errors) async {
    if (!_reportedActions.add(_actionKey(output))) return;
    final errorFile =
        await File(_errorPathForOutput(output)).create(recursive: true);
    await errorFile.writeAsString(jsonEncode(<dynamic>[actionDescription]
        .followedBy(errors
            .map((e) => [e.message, e.error, e.stackTrace?.toString() ?? '']))
        .toList()));
  }

  /// Indicate that the build steps which would produce [outputs] are failing
  /// due to a dependency and being skipped so no actuall error will be
  /// produced.
  Future<void> markSkipped(Iterable<GeneratedAssetNode> outputs) =>
      Future.wait(outputs.map((output) async {
        if (!_reportedActions.add(_actionKey(output))) return;
        await clean(output.phaseNumber, output.primaryInput);
      }));

  /// Log stored errors for any build steps which would output nodes in
  /// [failingNodes] which haven't already been reported.
  Future<void> reportErrors(Iterable<GeneratedAssetNode> failingNodes) {
    final errorFiles = <File>[];
    for (final failure in failingNodes) {
      final key = _actionKey(failure);
      if (!_reportedActions.add(key)) continue;
      errorFiles.add(File(_errorPathForOutput(failure)));
    }
    return Future.wait(errorFiles.map((errorFile) async {
      if (await errorFile.exists()) {
        final errorReports = jsonDecode(await errorFile.readAsString());
        final actionDescription = '${(errorReports as List).first} (cached)';
        final logger = Logger(actionDescription);
        for (final List error in errorReports.skip(1)) {
          final stackTraceString = error[2] as String;
          final stackTrace = stackTraceString.isEmpty
              ? null
              : StackTrace.fromString(stackTraceString);
          logger.severe(error[0], error[1], stackTrace);
        }
      }
    }));
  }
}

/// Matches the call to [Logger.severe] except the [message] and [error] are
/// eagerly converted to String.
class ErrorReport {
  final String message;
  final String error;
  final StackTrace stackTrace;
  ErrorReport(this.message, this.error, this.stackTrace);
}

String _actionKey(GeneratedAssetNode node) =>
    '${node.builderOptionsId} on ${node.primaryInput}';

String _errorPathForOutput(GeneratedAssetNode output) => p.join(
    p.fromUri(errorCachePath),
    output.id.package,
    '${output.phaseNumber}',
    p.fromUri(output.primaryInput.path));

String _errorPathForPrimaryInput(int phaseNumber, AssetId primaryInput) =>
    p.join(p.fromUri(errorCachePath), primaryInput.package, '$phaseNumber',
        p.fromUri(primaryInput.path));
