// Copyright (c) 2016, 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.7

import 'dart:async';
import 'dart:io';

import 'package:_fe_analyzer_shared/src/testing/annotated_code_helper.dart';
import 'package:async_helper/async_helper.dart';
import 'package:compiler/compiler.dart';
import 'package:expect/expect.dart';
import 'package:source_maps/source_maps.dart';

import '../helpers/memory_compiler.dart';

const List<String> TESTS = const <String>[
  '''
@{main}main() {
@{main}}
''',
  '''
@{main}main() {
  @{main}throw '';
@{main}}
''',
  '''
@{main}main() {
  @{main}return 0;
@{main}}
''',
  '''
import 'package:expect/expect.dart';
@{main}main() {
  @{main}test();
@{main}}

@pragma('dart2js:noInline')
@{test}test() {
@{test}}
''',
];

class Test {
  final String annotatedCode;
  final String code;
  final List<SourceLocation> expectedLocations;

  Test(this.annotatedCode, this.code, this.expectedLocations);
}

Test processTestCode(String code) {
  List<SourceLocation> expectedLocations = <SourceLocation>[];
  AnnotatedCode annotatedCode = new AnnotatedCode.fromText(code);
  for (Annotation annotation in annotatedCode.annotations) {
    String methodName = annotation.text;
    expectedLocations.add(
        new SourceLocation(methodName, annotation.lineNo, annotation.columnNo));
  }
  return new Test(code, annotatedCode.sourceCode, expectedLocations);
}

void main(List<String> arguments) {
  bool verbose = false;
  bool printJs = false;
  bool writeJs = false;
  List<int> indices;
  for (String arg in arguments) {
    if (arg == '-v') {
      verbose = true;
    } else if (arg == '--print-js') {
      printJs = true;
    } else if (arg == '--write-js') {
      writeJs = true;
    } else {
      int index = int.tryParse(arg);
      if (index != null) {
        indices ??= <int>[];
        if (index < 0 || index >= TESTS.length) {
          print('Index $index out of bounds: [0;${TESTS.length - 1}]');
        } else {
          indices.add(index);
        }
      }
    }
  }
  if (indices == null) {
    indices = new List<int>.generate(TESTS.length, (i) => i);
  }
  asyncTest(() async {
    for (int index in indices) {
      await runTest(index, processTestCode(TESTS[index]),
          printJs: printJs, writeJs: writeJs, verbose: verbose);
    }
  });
}

Future runTest(int index, Test test,
    {bool printJs: false, bool writeJs, bool verbose: false}) async {
  print("--$index------------------------------------------------------------");
  print("Compiling dart2js\n ${test.annotatedCode}");
  OutputCollector collector = new OutputCollector();
  List<String> options = <String>['--out=out.js', '--source-map=out.js.map'];
  CompilationResult compilationResult = await runCompiler(
      entryPoint: Uri.parse('memory:main.dart'),
      memorySourceFiles: {'main.dart': test.code},
      outputProvider: collector,
      options: options,
      unsafeToTouchSourceFiles: true);
  Expect.isTrue(compilationResult.isSuccess,
      "Unsuccessful compilation of test:\n${test.code}");
  String sourceMapText = collector.getOutput('', OutputType.sourceMap);
  SingleMapping sourceMap = parse(sourceMapText);
  if (writeJs) {
    new File('out.js')
        .writeAsStringSync(collector.getOutput('', OutputType.js));
    new File('out.js.map').writeAsStringSync(sourceMapText);
  }

  Set<SourceLocation> expectedLocations = test.expectedLocations.toSet();
  List<SourceLocation> actualLocations = <SourceLocation>[];
  List<SourceLocation> extraLocations = <SourceLocation>[];
  for (TargetLineEntry targetLineEntry in sourceMap.lines) {
    for (TargetEntry targetEntry in targetLineEntry.entries) {
      if (targetEntry.sourceUrlId != null &&
          sourceMap.urls[targetEntry.sourceUrlId] == 'memory:main.dart') {
        String methodName;
        if (targetEntry.sourceNameId != null) {
          methodName = sourceMap.names[targetEntry.sourceNameId];
        }
        SourceLocation location = new SourceLocation(methodName,
            targetEntry.sourceLine + 1, targetEntry.sourceColumn + 1);
        actualLocations.add(location);
        if (!expectedLocations.remove(location)) {
          extraLocations.add(location);
        }
      }
    }
  }

  if (expectedLocations.isNotEmpty) {
    print('--Missing source locations:---------------------------------------');
    AnnotatedCode annotatedCode = new AnnotatedCode(test.code, test.code, []);
    expectedLocations.forEach((l) => annotatedCode.addAnnotation(
        l.lineNo, l.columnNo, '/*', l.methodName, '*/'));
    print(annotatedCode.toText());
    print('------------------------------------------------------------------');
    Expect.isTrue(
        expectedLocations.isEmpty,
        "Missing source locations:\n${test.code}\n"
        "Actual:\n${actualLocations.join('\n')}\n"
        "Missing:\n${expectedLocations.join('\n')}\n");
  }
  if (extraLocations.isNotEmpty) {
    print('--Extra source locations:-----------------------------------------');
    AnnotatedCode annotatedCode = new AnnotatedCode(test.code, test.code, []);
    extraLocations.forEach((l) => annotatedCode.addAnnotation(
        l.lineNo, l.columnNo, '/*', l.methodName, '*/'));
    print(annotatedCode.toText());
    print('------------------------------------------------------------------');
    Expect.isTrue(
        extraLocations.isEmpty,
        "Extra source locations:\n${test.code}\n"
        "Actual:\n${actualLocations.join('\n')}\n"
        "Extra:\n${extraLocations.join('\n')}\n");
  }
}

class SourceLocation {
  final String methodName;
  final int lineNo;
  final int columnNo;

  SourceLocation(this.methodName, this.lineNo, this.columnNo);

  @override
  int get hashCode =>
      methodName.hashCode * 13 + lineNo.hashCode * 17 + columnNo.hashCode * 19;

  @override
  bool operator ==(other) {
    if (identical(this, other)) return true;
    if (other is! SourceLocation) return false;
    return methodName == other.methodName &&
        lineNo == other.lineNo &&
        columnNo == other.columnNo;
  }

  @override
  String toString() => '$methodName:$lineNo:$columnNo';
}
