// Copyright (c) 2015, 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:io';

import 'package:path/path.dart' as p;
import 'package:test/test.dart';
import 'package:test_process/test_process.dart';

final String testAppPath = p.join('test', 'test_files', 'test_app.dart');

const Duration timeout = Duration(seconds: 20);

Future<TestProcess> runTestApp(int openPort) => TestProcess.start(
      Platform.resolvedExecutable,
      [
        '--enable-vm-service=$openPort',
        '--pause_isolates_on_exit',
        '--branch-coverage',
        testAppPath
      ],
    );

List<Map<String, dynamic>> coverageDataFromJson(Map<String, dynamic> json) {
  expect(json.keys, unorderedEquals(<String>['type', 'coverage']));
  expect(json, containsPair('type', 'CodeCoverage'));

  return (json['coverage'] as List).cast<Map<String, dynamic>>();
}

final _versionPattern = RegExp('([0-9]+)\\.([0-9]+)\\.([0-9]+)');

bool platformVersionCheck(int minMajor, int minMinor) {
  final match = _versionPattern.matchAsPrefix(Platform.version);
  if (match == null) return false;
  if (match.groupCount < 3) return false;
  final major = int.parse(match.group(1)!);
  final minor = int.parse(match.group(2)!);
  return major > minMajor || (major == minMajor && minor >= minMinor);
}

/// Returns a mapping of (URL: (function_name: hit_count)) from [sources].
Map<String, Map<String, int>> functionInfoFromSources(
  Map<String, List<Map<dynamic, dynamic>>> sources,
) {
  Map<int, String> getFuncNames(List list) {
    return {
      for (var i = 0; i < list.length; i += 2)
        list[i] as int: list[i + 1] as String,
    };
  }

  Map<int, int> getFuncHits(List list) {
    return {
      for (var i = 0; i < list.length; i += 2)
        list[i] as int: list[i + 1] as int,
    };
  }

  return {
    for (var entry in sources.entries)
      entry.key: entry.value.fold(
        {},
        (previousValue, element) {
          expect(element['source'], entry.key);
          final names = getFuncNames(element['funcNames'] as List);
          final hits = getFuncHits(element['funcHits'] as List);

          for (var pair in hits.entries) {
            previousValue[names[pair.key]!] =
                (previousValue[names[pair.key]!] ?? 0) + pair.value;
          }

          return previousValue;
        },
      ),
  };
}

extension ListTestExtension on List {
  Map<String, List<Map<dynamic, dynamic>>> sources() => cast<Map>().fold(
        <String, List<Map>>{},
        (Map<String, List<Map>> map, value) {
          final sourceUri = value['source'] as String;
          map.putIfAbsent(sourceUri, () => <Map>[]).add(value);
          return map;
        },
      );
}
