// Copyright (c) 2023, 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/src/diagnostic/diagnostic.dart' as diag;
import 'package:test_reflective_loader/test_reflective_loader.dart';

import '../dart/resolution/context_collection_resolution.dart';

main() {
  defineReflectiveSuite(() {
    defineReflectiveTests(ExtensionTypeInheritedMemberConflictTest_extension2);
    defineReflectiveTests(
      ExtensionTypeInheritedMemberConflictTest_extensionAndNot,
    );
    defineReflectiveTests(
      ExtensionTypeInheritedMemberConflictTest_notExtension,
    );
  });
}

@reflectiveTest
class ExtensionTypeInheritedMemberConflictTest_extension2
    extends PubPackageResolutionTest {
  test_conflict() async {
    await assertErrorsInCode(
      '''
extension type A1(int it) {
  void foo() {}
}

extension type A2(int it) {
  void foo() {}
}

extension type B(int it) implements A1, A2 {}
''',
      [
        error(
          diag.extensionTypeInheritedMemberConflict,
          109,
          1,
          contextMessages: [message(testFile, 35, 3), message(testFile, 82, 3)],
        ),
      ],
    );
  }

  test_conflict_representationField() async {
    await assertErrorsInCode(
      '''
extension type A(String bar) {}

extension type B(String bar) {}

extension type C(String foo) implements A, B {}
''',
      [
        error(
          diag.extensionTypeInheritedMemberConflict,
          81,
          1,
          contextMessages: [message(testFile, 24, 3), message(testFile, 57, 3)],
        ),
      ],
    );
  }

  test_noConflict_redeclared() async {
    await assertNoErrorsInCode('''
extension type A1(int it) {
  void foo() {}
}

extension type A2(int it) {
  void foo() {}
}

extension type B(int it) implements A1, A2 {
  void foo() {}
}
''');
  }

  test_noConflict_sameDeclaration() async {
    await assertNoErrorsInCode('''
extension type A(int it) {
  void foo() {}
}

extension type B1(int it) implements A {}

extension type B2(int it) implements A {}

extension type C(int it) implements B1, B2 {}
''');
  }
}

@reflectiveTest
class ExtensionTypeInheritedMemberConflictTest_extensionAndNot
    extends PubPackageResolutionTest {
  test_conflict() async {
    await assertErrorsInCode(
      '''
class A {
  void foo() {}
}

extension type B(A it) {
  void foo() {}
}

extension type C(A it) implements A, B {}
''',
      [
        error(
          diag.extensionTypeInheritedMemberConflict,
          88,
          1,
          contextMessages: [message(testFile, 17, 3), message(testFile, 61, 3)],
        ),
      ],
    );
  }

  test_redeclared() async {
    await assertNoErrorsInCode('''
class A {
  void foo() {}
}

extension type B(A it) {
  void foo() {}
}

extension type C(A it) implements A, B {
  void foo() {}
}
''');
  }
}

@reflectiveTest
class ExtensionTypeInheritedMemberConflictTest_notExtension
    extends PubPackageResolutionTest {
  test_conflict() async {
    await assertErrorsInCode(
      '''
class A {
  void foo(int a) {}
}

class B {
  void foo(String a) {}
}

class C implements A, B {
  void foo(Object a) {}
}

extension type D(C it) implements A, B {}
''',
      [
        error(
          diag.extensionTypeInheritedMemberConflict,
          139,
          1,
          contextMessages: [message(testFile, 17, 3), message(testFile, 51, 3)],
        ),
      ],
    );
  }

  test_noConflict_notExtension_combined() async {
    await assertNoErrorsInCode('''
abstract class A<T> {
  (Object?, dynamic, dynamic) method(T t);
}

abstract class B<T> {
  (dynamic, Object?, dynamic) method(T t);
}

abstract class C<T> implements A<T>, B<T> {}

abstract class D<T> {
  (dynamic, dynamic, Object?) method(T t);
}

abstract class E<T> implements C<T>, D<T> {}

extension type F<T>(C<T> c) implements A<T>, B<T> {}

extension type G<T>(E<T> e) implements F<T>, D<T> {}
''');
  }

  test_noConflict_redeclared() async {
    await assertNoErrorsInCode('''
class A {
  void foo(int a) {}
}

class B {
  void foo(String a) {}
}

class C implements A, B {
  void foo(Object a) {}
}

extension type D(C it) implements A, B {
  void foo() {}
}
''');
  }

  test_noConflict_sameDeclaration() async {
    await assertNoErrorsInCode('''
class A {
  int foo() => 0;
}

class B1 extends A {}

class B2 extends A {}

abstract class C implements B1, B2 {}

extension type D(C it) implements B1, B2 {}
''');
  }
}
