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

import 'dart:convert' show json;
import 'dart:math' as math;

double _doNormal(
    {required double mean, required double stddev, required double x}) {
  return (1.0 / (stddev * math.sqrt(2.0 * math.pi))) *
      math.pow(math.e, -0.5 * math.pow((x - mean) / stddev, 2.0));
}

double _doMean(List<double> values) =>
    values.reduce((double x, double y) => x + y) / values.length;

double _doStddev(List<double> values, double mean) {
  double stddev = 0.0;
  for (final double value in values) {
    stddev += (value - mean) * (value - mean);
  }
  return math.sqrt(stddev / values.length);
}

double _doIntegral({
  required double Function(double) func,
  required double start,
  required double stop,
  required double resolution,
}) {
  double result = 0.0;
  while (start < stop) {
    final double value = func(start);
    result += resolution * value;
    start += resolution;
  }
  return result;
}

/// Probability is defined as the probability that the mean is within the
/// [margin] of the true value.
double _doProbability({required double mean, required double stddev, required double margin}) {
  return _doIntegral(
    func: (double x) => _doNormal(mean: mean, stddev: stddev, x: x),
    start: (1.0 - margin) * mean,
    stop: (1.0 + margin) * mean,
    resolution: 0.001,
  );
}

/// This class knows how to format benchmark results for machine and human
/// consumption.
///

/// Example:
///
///     BenchmarkResultPrinter printer = new BenchmarkResultPrinter();
///     printer.add(
///       description: 'Average frame time',
///       value: averageFrameTime,
///       unit: 'ms',
///       name: 'average_frame_time',
///     );
///     printer.printToStdout();
///
class BenchmarkResultPrinter {

  final List<_BenchmarkResult> _results = <_BenchmarkResult>[];

  /// Adds a benchmark result to the list of results.
  ///
  /// [description] is a human-readable description of the result. [value] is a
  /// result value. [unit] is the unit of measurement, such as "ms", "km", "h".
  /// [name] is a computer-readable name of the result used as a key in the JSON
  /// serialization of the results.
  void addResult({ required String description, required double value, required String unit, required String name }) {
    _results.add(_BenchmarkResult(description, value, unit, name));
  }

  /// Adds a benchmark result to the list of results and a probability of that
  /// result.
  ///
  /// The probability is calculated as the probability that the mean is +- 5% of
  /// the true value.
  ///
  /// See also [addResult].
  void addResultStatistics({
    required String description,
    required List<double> values,
    required String unit,
    required String name,
  }) {
    final double mean = _doMean(values);
    final double stddev = _doStddev(values, mean);
    const double margin = 0.05;
    final double probability = _doProbability(mean: mean, stddev: stddev, margin: margin);
    _results.add(_BenchmarkResult(description, mean, unit, name));
    _results.add(_BenchmarkResult('$description - probability margin of error $margin', probability,
        'percent', '${name}_probability_5pct'));
  }

  /// Prints the results added via [addResult] to standard output, once as JSON
  /// for computer consumption and once formatted as plain text for humans.
  void printToStdout() {
    // IMPORTANT: keep these values in sync with dev/devicelab/bin/tasks/microbenchmarks.dart
    const String jsonStart = '================ RESULTS ================';
    const String jsonEnd = '================ FORMATTED ==============';
    const String jsonPrefix = ':::JSON:::';

    print(jsonStart);
    print('$jsonPrefix ${_printJson()}');
    print(jsonEnd);
    print(_printPlainText());
  }

  String _printJson() {
    final Map<String, double> results = <String, double>{};
    for (final _BenchmarkResult result in _results) {
      results[result.name] = result.value;
    }
    return json.encode(results);
  }

  String _printPlainText() {
    final StringBuffer buf = StringBuffer();
    for (final _BenchmarkResult result in _results) {
      buf.writeln('${result.description}: ${result.value.toStringAsFixed(1)} ${result.unit}');
    }
    return buf.toString();
  }
}

class _BenchmarkResult {
  _BenchmarkResult(this.description, this.value, this.unit, this.name);

  /// Human-readable description of the result, e.g. "Average frame time".
  final String description;

  /// Result value that in agreement with [unit].
  final double value;

  /// Unit of measurement that is in agreement with [value].
  final String unit;

  /// Computer-readable name of the result.
  final String name;
}
