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

// @dart=2.9

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;
import 'package:meta/meta.dart';

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;
  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/dart2/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();
    }
  }
}
