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

import "package:yaml/yaml.dart" show YamlMap, loadYamlNode;

import 'package:testing/testing.dart'
    show Chain, ChainContext, Result, Step, TestDescription, runMe;

import 'testing_utils.dart' show checkEnvironment;

import 'parser_suite.dart'
    show ListenerStep, ParserTestListenerWithMessageFormatting;

main([List<String> arguments = const []]) => runMe(
      arguments,
      createContext,
      configurationPath: "../testing.json",
    );

Future<Context> createContext(
    Chain suite, Map<String, String> environment) async {
  const Set<String> knownEnvironmentKeys = {};
  checkEnvironment(environment, knownEnvironmentKeys);

  return new Context(suite.name);
}

class Context extends ChainContext {
  final String suiteName;

  Context(this.suiteName);

  final List<Step> steps = const <Step>[
    const ListenerCompareStep(),
  ];
}

class ListenerCompareStep
    extends Step<TestDescription, TestDescription, Context> {
  const ListenerCompareStep();

  String get name => "listenerCompare";

  Future<Result<TestDescription>> run(
      TestDescription description, Context context) {
    Uri uri = description.uri;
    String contents = new File.fromUri(uri).readAsStringSync();
    YamlMap yaml = loadYamlNode(contents, sourceUrl: uri);
    List<Uri> files =
        (yaml["files"] as List).map((s) => uri.resolve(s)).toList();
    Set<String> filters = new Set<String>.from(yaml["filters"] ?? []);
    Set<String> ignored = new Set<String>.from(yaml["ignored"] ?? []);

    ParserTestListenerWithMessageFormatting parserTestListenerFirst =
        ListenerStep.doListenerParsing(
      files[0],
      context.suiteName,
      description.shortName,
    );
    if (parserTestListenerFirst == null) {
      return Future.value(crash(description, StackTrace.current));
    }

    for (int i = 1; i < files.length; i++) {
      ParserTestListenerWithMessageFormatting parserTestListener =
          ListenerStep.doListenerParsing(
        files[i],
        context.suiteName,
        description.shortName,
      );
      if (parserTestListener == null) {
        return Future.value(crash(description, StackTrace.current));
      }
      String compareResult = compare(
          parserTestListenerFirst, parserTestListener, filters, ignored);
      if (compareResult != null) {
        return Future.value(
            fail(description, compareResult, StackTrace.current));
      }
    }

    return new Future.value(new Result<TestDescription>.pass(description));
  }

  String compare(
      ParserTestListenerWithMessageFormatting a,
      ParserTestListenerWithMessageFormatting b,
      Set<String> filters,
      Set<String> ignored) {
    List<String> aLines = a.sb.toString().split("\n");
    List<String> bLines = b.sb.toString().split("\n");

    bool doRemoveListenerArguments =
        filters.contains("ignoreListenerArguments");

    int aIndex = 0;
    int bIndex = 0;
    while (aIndex < aLines.length && bIndex < bLines.length) {
      String aLine = aLines[aIndex];
      String bLine = bLines[bIndex];
      if (doRemoveListenerArguments) {
        aLine = removeListenerArguments(aLine);
        bLine = removeListenerArguments(bLine);
      }
      bool anyIgnored = false;
      if (ignored.contains(aLine.trim())) {
        anyIgnored = true;
        aIndex++;
      }
      if (ignored.contains(bLine.trim())) {
        anyIgnored = true;
        bIndex++;
      }
      if (anyIgnored) continue;
      if (aLine != bLine) {
        return "Disagreement: '${aLine}' vs '${bLine}'";
      }
      aIndex++;
      bIndex++;
    }

    // Any trailing lines?
    while (aIndex < aLines.length) {
      String aLine = aLines[aIndex];
      if (doRemoveListenerArguments) {
        aLine = removeListenerArguments(aLine);
      }
      if (ignored.contains(aLine.trim())) {
        aIndex++;
        continue;
      }
      return "Unmatched line at end: '$aLine'";
    }
    while (bIndex < bLines.length) {
      String bLine = bLines[bIndex];
      if (doRemoveListenerArguments) {
        bLine = removeListenerArguments(bLine);
      }
      if (ignored.contains(bLine.trim())) {
        bIndex++;
        continue;
      }
      return "Unmatched line at end: '$bLine'";
    }
    return null;
  }

  String removeListenerArguments(String s) {
    int index = s.indexOf("(");
    if (index < 0) return s;
    return s.substring(0, index);
  }
}
