// Copyright (c) 2019, 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/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/type_provider.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/element/type_system.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:nnbd_migration/instrumentation.dart';
import 'package:nnbd_migration/src/conditional_discard.dart';
import 'package:nnbd_migration/src/decorated_class_hierarchy.dart';
import 'package:nnbd_migration/src/decorated_type.dart';
import 'package:nnbd_migration/src/edge_builder.dart';
import 'package:nnbd_migration/src/expression_checks.dart';
import 'package:nnbd_migration/src/node_builder.dart';
import 'package:nnbd_migration/src/nullability_node.dart';
import 'package:nnbd_migration/src/nullability_node_target.dart';
import 'package:nnbd_migration/src/variables.dart';
import 'package:test/test.dart';

import 'abstract_single_unit.dart';

/// A [NodeMatcher] that matches any node, and records what node it matched to.
class AnyNodeMatcher extends _RecordingNodeMatcher {
  @override
  bool matches(NullabilityNode? node) {
    return true;
  }
}

/// Mixin allowing unit tests to create decorated types easily.
mixin DecoratedTypeTester implements DecoratedTypeTesterBase {
  int nodeId = 0;

  NullabilityNode get always => graph.always;

  DecoratedType get bottom => DecoratedType(typeProvider.bottomType, never);

  DecoratedType get dynamic_ => DecoratedType(typeProvider.dynamicType, always);

  NullabilityNode get never => graph.never;

  DecoratedType get null_ => DecoratedType(typeProvider.nullType, always);

  DecoratedType get void_ => DecoratedType(typeProvider.voidType, always);

  DecoratedType function(DecoratedType returnType,
      {List<DecoratedType> required = const [],
      List<DecoratedType> positional = const [],
      Map<String, DecoratedType> named = const {},
      List<TypeParameterElement> typeFormals = const [],
      NullabilityNode? node}) {
    int i = 0;
    var parameters = required
        .map((t) => ParameterElementImpl.synthetic(
            'p${i++}', t.type!, ParameterKind.REQUIRED))
        .toList();
    parameters.addAll(positional.map((t) => ParameterElementImpl.synthetic(
        'p${i++}', t.type!, ParameterKind.POSITIONAL)));
    parameters.addAll(named.entries.map((e) => ParameterElementImpl.synthetic(
        e.key, e.value.type!, ParameterKind.NAMED)));
    return DecoratedType(
        FunctionTypeImpl(
          typeFormals: typeFormals,
          parameters: parameters,
          returnType: returnType.type!,
          nullabilitySuffix: NullabilitySuffix.star,
        ),
        node ?? newNode(),
        returnType: returnType,
        positionalParameters: required.toList()..addAll(positional),
        namedParameters: named);
  }

  DecoratedType future(DecoratedType parameter, {NullabilityNode? node}) {
    return DecoratedType(
        typeProvider.futureType(parameter.type!), node ?? newNode(),
        typeArguments: [parameter]);
  }

  DecoratedType futureOr(DecoratedType parameter, {NullabilityNode? node}) {
    return DecoratedType(
        typeProvider.futureOrType(parameter.type!), node ?? newNode(),
        typeArguments: [parameter]);
  }

  DecoratedType int_({NullabilityNode? node}) =>
      DecoratedType(typeProvider.intType, node ?? newNode());

  DecoratedType iterable(DecoratedType elementType, {NullabilityNode? node}) =>
      DecoratedType(
          typeProvider.iterableType(elementType.type!), node ?? newNode(),
          typeArguments: [elementType]);

  DecoratedType list(DecoratedType elementType, {NullabilityNode? node}) =>
      DecoratedType(typeProvider.listType(elementType.type!), node ?? newNode(),
          typeArguments: [elementType]);

  NullabilityNode newNode() => NullabilityNode.forTypeAnnotation(
      NullabilityNodeTarget.text('node ${nodeId++}'));

  DecoratedType num_({NullabilityNode? node}) =>
      DecoratedType(typeProvider.numType, node ?? newNode());

  DecoratedType object({NullabilityNode? node}) =>
      DecoratedType(typeProvider.objectType, node ?? newNode());

  TypeParameterElement typeParameter(String name, DecoratedType bound) {
    var element = TypeParameterElementImpl.synthetic(name);
    element.bound = bound.type;
    decoratedTypeParameterBounds.put(element, bound);
    return element;
  }

  DecoratedType typeParameterType(TypeParameterElement typeParameter,
      {NullabilityNode? node}) {
    return DecoratedType(
      typeParameter.instantiate(
        nullabilitySuffix: NullabilitySuffix.star,
      ),
      node ?? newNode(),
    );
  }
}

/// Base functionality that must be implemented by classes mixing in
/// [DecoratedTypeTester].
abstract class DecoratedTypeTesterBase {
  DecoratedTypeParameterBounds get decoratedTypeParameterBounds;

  NullabilityGraph get graph;

  TypeProvider get typeProvider;
}

class EdgeBuilderTestBase extends MigrationVisitorTestBase {
  DecoratedClassHierarchy? decoratedClassHierarchy;

  /// Analyzes the given source code, producing constraint variables and
  /// constraints for it.
  @override
  Future<CompilationUnit> analyze(String code) async {
    var unit = await super.analyze(code);
    decoratedClassHierarchy = DecoratedClassHierarchy(variables, graph);
    unit.accept(EdgeBuilder(
        typeProvider,
        typeSystem,
        variables,
        graph,
        testSource,
        null,
        decoratedClassHierarchy,
        unit.declaredElement!.library));
    return unit;
  }
}

/// Mixin allowing unit tests to check for the presence of graph edges.
mixin EdgeTester {
  /// Gets the set of all nodes pointed to by always, plus always itself.
  Set<NullabilityNode> get alwaysPlus {
    var result = <NullabilityNode>{graph.always};
    for (var edge in getEdges(graph.always, anyNode)) {
      if (edge.guards.isEmpty) {
        result.add(edge.destinationNode);
      }
    }
    return result;
  }

  /// Returns a [NodeMatcher] that matches any node whatsoever.
  AnyNodeMatcher get anyNode => AnyNodeMatcher();

  NullabilityGraphForTesting get graph;

  /// Gets the transitive closure of all nodes with hard edges pointing to
  /// never, plus never itself.
  Set<NullabilityNode?> get neverClosure {
    var result = <NullabilityNode?>{};
    var pending = <NullabilityNode?>[graph.never];
    while (pending.isNotEmpty) {
      var node = pending.removeLast();
      if (result.add(node)) {
        for (var edge in getEdges(anyNode, node)) {
          pending.add(edge.sourceNode);
        }
      }
    }
    return result;
  }

  /// Gets the set of nodes with hard edges pointing to never.
  Set<NullabilityNode?> get pointsToNever {
    return {for (var edge in getEdges(anyNode, graph.never)) edge.sourceNode};
  }

  /// Asserts that a dummy edge exists from [source] to always.
  NullabilityEdge assertDummyEdge(Object? source) =>
      assertEdge(source, graph.always, hard: false, checkable: false);

  /// Asserts that an edge exists with a node matching [source] and a node
  /// matching [destination], and with the given [hard]ness and [guards].
  ///
  /// [source] and [destination] are converted to [NodeMatcher] objects if they
  /// aren't already.  In practice this means that the caller can pass in either
  /// a [NodeMatcher] or a [NullabilityNode].
  NullabilityEdge assertEdge(Object? source, Object? destination,
      {required bool hard,
      bool checkable = true,
      bool isSetupAssignment = false,
      Object guards = isEmpty,
      Object? codeReference}) {
    var edges = getEdges(source, destination);
    if (edges.isEmpty) {
      fail('Expected edge $source -> $destination, found none');
    } else if (edges.length != 1) {
      fail('Found multiple edges $source -> $destination');
    } else {
      var edge = edges[0];
      expect(edge.isHard, hard);
      expect(edge.isCheckable, checkable);
      expect(edge.isSetupAssignment, isSetupAssignment);
      expect(edge.guards, guards);
      if (codeReference != null) {
        expect(edge.codeReference, codeReference);
      }
      return edge;
    }
  }

  /// Asserts that no edge exists with a node matching [source] and a node
  /// matching [destination].
  ///
  /// [source] and [destination] are converted to [NodeMatcher] objects if they
  /// aren't already.  In practice this means that the caller can pass in either
  /// a [NodeMatcher] or a [NullabilityNode].
  void assertNoEdge(Object? source, Object? destination) {
    var edges = getEdges(source, destination);
    if (edges.isNotEmpty) {
      fail('Expected no edge $source -> $destination, found $edges');
    }
  }

  /// Asserts that a union-type edge exists between nodes [x] and [y].
  ///
  /// [x] and [y] are converted to [NodeMatcher] objects if they aren't already.
  /// In practice this means that the caller can pass in either a [NodeMatcher]
  /// or a [NullabilityNode].
  void assertUnion(Object? x, Object? y) {
    var edges = getEdges(x, y);
    for (var edge in edges) {
      if (edge.isUnion) {
        expect(edge.upstreamNodes, hasLength(1));
        return;
      }
    }
    fail('Expected union between $x and $y, not found');
  }

  /// Gets a list of all edges whose source matches [source] and whose
  /// destination matches [destination].
  ///
  /// [source] and [destination] are converted to [NodeMatcher] objects if they
  /// aren't already.  In practice this means that the caller can pass in either
  /// a [NodeMatcher] or a [NullabilityNode].
  List<NullabilityEdge> getEdges(Object? source, Object? destination) {
    var sourceMatcher = NodeMatcher(source);
    var destinationMatcher = NodeMatcher(destination);
    var result = <NullabilityEdge>[];
    for (var edge in graph.getAllEdges()) {
      if (sourceMatcher.matches(edge.sourceNode) &&
          destinationMatcher.matches(edge.destinationNode)) {
        sourceMatcher.matched(edge.sourceNode);
        destinationMatcher.matched(edge.destinationNode);
        result.add(edge);
      }
    }
    return result;
  }

  /// Returns a [NodeMatcher] that matches any node in the given set.
  NodeSetMatcher inSet(Set<NullabilityNode?> nodes) => NodeSetMatcher(nodes);

  /// Creates a [NodeMatcher] matching a substitution node whose inner and outer
  /// nodes match [inner] and [outer].
  ///
  /// [inner] and [outer] are converted to [NodeMatcher] objects if they aren't
  /// already.  In practice this means that the caller can pass in either a
  /// [NodeMatcher] or a [NullabilityNode].
  NodeMatcher substitutionNode(Object? inner, Object? outer) =>
      _SubstitutionNodeMatcher(NodeMatcher(inner), NodeMatcher(outer));
}

/// Mock representation of constraint variables.
class InstrumentedVariables extends Variables {
  final _conditionalDiscard = <AstNode, ConditionalDiscard>{};

  final _decoratedExpressionTypes = <Expression, DecoratedType?>{};

  final _expressionChecks = <Expression, ExpressionChecksOrigin>{};

  InstrumentedVariables(NullabilityGraph graph, TypeProvider typeProvider)
      : super(graph, typeProvider);

  /// Gets the [ExpressionChecks] associated with the given [expression].
  ExpressionChecksOrigin? checkExpression(Expression expression) =>
      _expressionChecks[_normalizeExpression(expression)];

  /// Gets the [conditionalDiscard] associated with the given [expression].
  ConditionalDiscard? conditionalDiscard(AstNode node) =>
      _conditionalDiscard[node];

  /// Gets the [DecoratedType] associated with the given [expression].
  DecoratedType? decoratedExpressionType(Expression expression) =>
      _decoratedExpressionTypes[_normalizeExpression(expression)];

  @override
  void recordConditionalDiscard(
      Source? source, AstNode node, ConditionalDiscard conditionalDiscard) {
    _conditionalDiscard[node] = conditionalDiscard;
    super.recordConditionalDiscard(source, node, conditionalDiscard);
  }

  void recordDecoratedExpressionType(Expression node, DecoratedType? type) {
    super.recordDecoratedExpressionType(node, type);
    _decoratedExpressionTypes[_normalizeExpression(node)] = type;
  }

  @override
  void recordExpressionChecks(
      Source? source, Expression expression, ExpressionChecksOrigin origin) {
    super.recordExpressionChecks(source, expression, origin);
    _expressionChecks[_normalizeExpression(expression)] = origin;
  }

  /// Unwraps any parentheses surrounding [expression].
  Expression _normalizeExpression(Expression expression) {
    while (expression is ParenthesizedExpression) {
      expression = expression.expression;
    }
    return expression;
  }
}

class MigrationVisitorTestBase extends AbstractSingleUnitTest with EdgeTester {
  InstrumentedVariables? variables;

  final NullabilityGraphForTesting graph;

  final decoratedTypeParameterBounds = DecoratedTypeParameterBounds();

  MigrationVisitorTestBase() : this._(NullabilityGraphForTesting());

  MigrationVisitorTestBase._(this.graph);

  NullabilityNode get always => graph.always;

  NullabilityNode get never => graph.never;

  TypeProvider get typeProvider => testAnalysisResult.typeProvider;

  TypeSystemImpl get typeSystem =>
      testAnalysisResult.typeSystem as TypeSystemImpl;

  Future<CompilationUnit> analyze(String code) async {
    await resolveTestUnit(code);
    variables = InstrumentedVariables(graph, typeProvider);
    testUnit!
        .accept(NodeBuilder(variables, testSource, null, graph, typeProvider));
    return testUnit!;
  }

  /// Gets the [DecoratedType] associated with the constructor declaration whose
  /// name matches [search].
  DecoratedType decoratedConstructorDeclaration(String search) => variables!
      .decoratedElementType(findNode.constructor(search).declaredElement!);

  Map<ClassElement, DecoratedType?> decoratedDirectSupertypes(String name) {
    return variables!.decoratedDirectSupertypes(findElement.classOrMixin(name));
  }

  /// Gets the [DecoratedType] associated with the generic function type
  /// annotation whose text is [text].
  DecoratedType decoratedGenericFunctionTypeAnnotation(String text) {
    return variables!.decoratedTypeAnnotation(
        testSource, findNode.genericFunctionType(text));
  }

  /// Gets the [DecoratedType] associated with the method declaration whose
  /// name matches [search].
  DecoratedType decoratedMethodType(String search) =>
      variables!.decoratedElementType(
          findNode.methodDeclaration(search).declaredElement!);

  /// Gets the [DecoratedType] associated with the type annotation whose text
  /// is [text].
  DecoratedType decoratedTypeAnnotation(String text) {
    return variables!
        .decoratedTypeAnnotation(testSource, findNode.typeAnnotation(text));
  }

  /// Gets the [ConditionalDiscard] information associated with the collection
  /// element whose text is [text].
  ConditionalDiscard? elementDiscard(String text) {
    return variables!.conditionalDiscard(findNode.collectionElement(text));
  }

  /// Returns a [Matcher] that matches a [CodeReference] pointing to the given
  /// file [offset], with the given [function] name.
  TypeMatcher<CodeReference> matchCodeRef(
      {required int offset, required String function}) {
    var location = testUnit!.lineInfo.getLocation(offset);
    return TypeMatcher<CodeReference>()
        .having((cr) => cr.line, 'line', location.lineNumber)
        .having((cr) => cr.column, 'column', location.columnNumber)
        .having((cr) => cr.function, 'function', function);
  }

  void setUp() {
    DecoratedTypeParameterBounds.current = decoratedTypeParameterBounds;
    super.setUp();
  }

  /// Gets the [ConditionalDiscard] information associated with the statement
  /// whose text is [text].
  ConditionalDiscard? statementDiscard(String text) {
    return variables!.conditionalDiscard(findNode.statement(text));
  }

  void tearDown() {
    DecoratedTypeParameterBounds.current = null;
    super.tearDown();
  }
}

/// Abstract base class representing a thing that can be matched against
/// nullability nodes.
abstract class NodeMatcher {
  factory NodeMatcher(Object? expectation) {
    if (expectation is NodeMatcher) return expectation;
    if (expectation is NullabilityNode) return _ExactNodeMatcher(expectation);
    fail(
        'Unclear how to match node expectation of type ${expectation.runtimeType}');
  }

  void matched(NullabilityNode? node);

  bool matches(NullabilityNode? node);
}

/// A [NodeMatcher] that matches any node contained in the given set.
class NodeSetMatcher extends _RecordingNodeMatcher {
  final Set<NullabilityNode?> _targetSet;

  NodeSetMatcher(this._targetSet);

  @override
  bool matches(NullabilityNode? node) => _targetSet.contains(node);
}

/// A [NodeMatcher] that matches exactly one node.
class _ExactNodeMatcher implements NodeMatcher {
  final NullabilityNode _expectation;

  _ExactNodeMatcher(this._expectation);

  @override
  void matched(NullabilityNode? node) {}

  @override
  bool matches(NullabilityNode? node) => node == _expectation;
}

/// Base class for [NodeMatcher]s that remember which nodes were matched.
abstract class _RecordingNodeMatcher implements NodeMatcher {
  final List<NullabilityNode?> _matchingNodes = [];

  NullabilityNode? get matchingNode => _matchingNodes.single;

  @override
  void matched(NullabilityNode? node) {
    _matchingNodes.add(node);
  }
}

/// A [NodeMatcher] that matches a substitution node with the given inner and
/// outer nodes.
class _SubstitutionNodeMatcher implements NodeMatcher {
  final NodeMatcher inner;
  final NodeMatcher outer;

  _SubstitutionNodeMatcher(this.inner, this.outer);

  @override
  void matched(NullabilityNode? node) {
    if (node is NullabilityNodeForSubstitution) {
      inner.matched(node.innerNode);
      outer.matched(node.outerNode);
    } else {
      throw StateError(
          'matched should only be called on nodes for which matches returned '
          'true');
    }
  }

  @override
  bool matches(NullabilityNode? node) {
    return node is NullabilityNodeForSubstitution &&
        inner.matches(node.innerNode) &&
        outer.matches(node.outerNode);
  }
}
