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

import 'package:analyzer/dart/analysis/utilities.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
import 'package:analyzer/src/error/codes.dart';
import 'package:test/test.dart';
import 'package:test_reflective_loader/test_reflective_loader.dart';

import '../../../generated/elements_types_mixin.dart';
import 'context_collection_resolution.dart';

main() {
  defineReflectiveSuite(() {
    defineReflectiveTests(MacroResolutionTest);
  });
}

@reflectiveTest
class MacroResolutionTest extends PubPackageResolutionTest
    with ElementsTypesMixin {
  @override
  void setUp() {
    super.setUp();

    newFile('$testPackageLibPath/macro_annotations.dart', content: r'''
library analyzer.macro.annotations;
const autoConstructor = 0;
const observable = 0;
''');
  }

  test_autoConstructor() async {
    var code = r'''
import 'macro_annotations.dart';

@autoConstructor
class A {
  final int a;
}

void f() {
  A(a: 0);
}
''';

    // No diagnostics, specifically:
    // 1. The constructor `A()` is declared.
    // 2. The final field `a` is not marked, because the macro-generated
    //    constructor does initialize it.
    await assertNoErrorsInCode(code);

    _assertResolvedUnitWithParsed(code);
  }

  test_errors_parse_shiftToWritten() async {
    await assertErrorsInCode(r'''
import 'macro_annotations.dart';

class A {
  @observable
  int _foo = 0;
}

int a = 0
''', [
      error(ParserErrorCode.EXPECTED_TOKEN, 85, 1),
    ]);
  }

  test_errors_resolution_removeInGenerated() async {
    // The generated `set foo(int x) { _foo = x; }` has an error, it attempts
    // to assign to a final field `_foo`. But this error does not exist in
    // the written code, so it is not present.
    await assertNoErrorsInCode(r'''
import 'macro_annotations.dart';

class A {
  @observable
  final int _foo = 0;
}
''');
  }

  test_errors_resolution_shiftToWritten() async {
    await assertErrorsInCode(r'''
import 'macro_annotations.dart';

class A {
  @observable
  int _foo = 0;
}

notInt a = 0;
''', [
      error(CompileTimeErrorCode.UNDEFINED_CLASS, 77, 6),
    ]);
  }

  test_observable() async {
    var code = r'''
import 'macro_annotations.dart';

class A {
  @observable
  int _foo = 0;
}

void f(A a) {
  a.foo;
  a.foo = 2;
}
''';

    // No diagnostics, such as unused `_foo`.
    // We generate a getter/setter pair, so it is used.
    await assertNoErrorsInCode(code);

    _assertResolvedUnitWithParsed(code);
  }

  void _assertResolvedUnitWithParsed(String code) {
    // The resolved content is the original code.
    expect(result.content, code);

    var resolvedUnit = result.unit;
    var parsedUnit = parseString(content: code).unit;

    // The token stream was patched to keep only tokens that existed in the
    // original code.
    _assertEqualTokens(resolvedUnit, parsedUnit);

    // The AST was patched to keep only nodes that existed in the
    // original code.
    var resolvedTokenString = _nodeTokenString(resolvedUnit);
    var parsedTokenString = _nodeTokenString(parsedUnit);
    expect(resolvedTokenString, parsedTokenString);
  }

  static void _assertEqualTokens(AstNode first, AstNode second) {
    var firstToken = first.beginToken;
    var secondToken = second.beginToken;
    while (true) {
      if (firstToken == first.endToken && secondToken == second.endToken) {
        break;
      }
      expect(firstToken.lexeme, secondToken.lexeme);
      expect(firstToken.offset, secondToken.offset);
      firstToken = firstToken.next!;
      secondToken = secondToken.next!;
    }
  }

  /// Return the string dump of all tokens in [node] and its children.
  static String _nodeTokenString(AstNode node) {
    var tokens = <Token>[];
    node.accept(
      _RecursiveTokenCollector(tokens),
    );

    // `AstNode.childEntities` does not return tokens in any specific order.
    // So, we sort them to make the sequence look reasonable.
    tokens.sort((a, b) => a.offset - b.offset);

    var buffer = StringBuffer();
    for (var token in tokens) {
      buffer.writeln('${token.lexeme} @${token.offset}');
    }
    return buffer.toString();
  }
}

class _RecursiveTokenCollector extends GeneralizingAstVisitor<void> {
  final List<Token> _tokens;

  _RecursiveTokenCollector(this._tokens);

  @override
  void visitNode(AstNode node) {
    _tokens.addAll(
      node.childEntities.whereType<Token>(),
    );
    super.visitNode(node);
  }
}
