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

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

import 'package:async_helper/async_helper.dart';
import 'package:compiler/compiler_new.dart';
import 'package:expect/expect.dart';
import 'package:source_maps/source_maps.dart';
import 'package:front_end/src/testing/annotated_code_helper.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);
  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, []);
    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, []);
    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';
}
