// Copyright (c) 2019, 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 'dart:isolate';
import 'dart:typed_data';

import 'package:benchmark_harness/benchmark_harness.dart' show BenchmarkBase;

class JsonDecodingBenchmark {
  JsonDecodingBenchmark(this.name,
      {required this.sample,
      required this.numTasks,
      required this.useSendAndExit});

  Future<void> report() async {
    final stopwatch = Stopwatch()..start();
    // Benchmark harness counts 10 iterations as one.
    for (int i = 0; i < 10; i++) {
      final decodedFutures = <Future>[];
      for (int i = 0; i < numTasks; i++) {
        decodedFutures.add(decodeJson(useSendAndExit, sample));
      }
      await Future.wait(decodedFutures);
    }

    print('$name(RunTime): ${stopwatch.elapsedMicroseconds} us.');
  }

  final String name;
  final Uint8List sample;
  final int numTasks;
  final bool useSendAndExit;
}

Uint8List createSampleJson(final size) {
  final list = List.generate(size, (i) => i);
  final map = <dynamic, dynamic>{};
  for (int i = 0; i < size; i++) {
    map['$i'] = list;
  }
  return utf8.encode(json.encode(map));
}

class JsonDecodeRequest {
  final bool useSendAndExit;
  final SendPort sendPort;
  final Uint8List encodedJson;
  const JsonDecodeRequest(this.useSendAndExit, this.sendPort, this.encodedJson);
}

Future<Map> decodeJson(bool useSendAndExit, Uint8List encodedJson) async {
  final port = ReceivePort();
  final inbox = StreamIterator<dynamic>(port);
  final completer = Completer<bool>();
  final workerExitedPort = RawReceivePort((v) {
    completer.complete(true);
  });
  final workerErroredPort = RawReceivePort((v) {
    stderr.writeln('worker errored out $v');
    completer.completeError(true);
  });
  await Isolate.spawn(jsonDecodingIsolate,
      JsonDecodeRequest(useSendAndExit, port.sendPort, encodedJson),
      onError: workerErroredPort.sendPort, onExit: workerExitedPort.sendPort);
  await completer.future;
  workerExitedPort.close();
  workerErroredPort.close();
  await inbox.moveNext();
  final decodedJson = inbox.current as Map;
  port.close();
  return decodedJson;
}

Future<void> jsonDecodingIsolate(JsonDecodeRequest request) async {
  final result = json.decode(utf8.decode(request.encodedJson));
  if (request.useSendAndExit) {
    Isolate.exit(request.sendPort, result);
  } else {
    request.sendPort.send(result);
  }
}

class SyncJsonDecodingBenchmark extends BenchmarkBase {
  SyncJsonDecodingBenchmark(String name,
      {required this.sample, required this.iterations})
      : super(name);

  @override
  void run() {
    int l = 0;
    for (int i = 0; i < iterations; i++) {
      final Map map = json.decode(utf8.decode(sample));
      l += map.length;
    }
    assert(l > 0);
  }

  final Uint8List sample;
  final int iterations;
}

class BenchmarkConfig {
  BenchmarkConfig(this.suffix, this.sample);

  final String suffix;
  final Uint8List sample;
}

Future<void> main() async {
  final jsonString =
      File('benchmarks/IsolateJson/dart/sample.json').readAsStringSync();
  final json250KB = utf8.encode(jsonString); // 294356 bytes
  final decoded = json.decode(utf8.decode(json250KB));
  final decoded1MB = <dynamic, dynamic>{
    '1': decoded['1'],
    '2': decoded['1'],
    '3': decoded['1'],
    '4': decoded['1'],
  };
  final json1MB = utf8.encode(json.encode(decoded1MB)); // 1177397 bytes
  decoded['1'] = (decoded['1'] as List).sublist(0, 200);
  final json100KB = utf8.encode(json.encode(decoded)); // 104685 bytes
  decoded['1'] = (decoded['1'] as List).sublist(0, 100);
  final json50KB = utf8.encode(json.encode(decoded)); // 51760 bytes

  final configs = <BenchmarkConfig>[
    BenchmarkConfig('50KB', json50KB),
    BenchmarkConfig('100KB', json100KB),
    BenchmarkConfig('250KB', json250KB),
    BenchmarkConfig('1MB', json1MB),
  ];

  for (final config in configs) {
    for (final iterations in <int>[1, 4]) {
      await JsonDecodingBenchmark(
              'IsolateJson.Decode${config.suffix}x$iterations',
              useSendAndExit: false,
              sample: config.sample,
              numTasks: iterations)
          .report();
      await JsonDecodingBenchmark(
              'IsolateJson.SendAndExit_Decode${config.suffix}x$iterations',
              useSendAndExit: true,
              sample: config.sample,
              numTasks: iterations)
          .report();
      SyncJsonDecodingBenchmark(
              'IsolateJson.SyncDecode${config.suffix}x$iterations',
              sample: config.sample,
              iterations: iterations)
          .report();
    }
  }
}
