// Copyright 2014 The Flutter Authors. 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/results.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/visitor.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:path/path.dart' as path;

import '../utils.dart';
import 'analyze.dart';

// The comment pattern representing the "flutter_ignore" inline directive that
// indicates the line should be exempt from the stopwatch check.
final Pattern _ignoreStopwatch = RegExp(r'// flutter_ignore: .*stopwatch .*\(see analyze\.dart\)');

/// Use of Stopwatches can introduce test flakes as the logical time of a
/// stopwatch can fall out of sync with the mocked time of FakeAsync in testing.
/// The Clock object provides a safe stopwatch instead, which is paired with
/// FakeAsync as part of the test binding.
final AnalyzeRule noStopwatches = _NoStopwatches();

class _NoStopwatches implements AnalyzeRule {
  final Map<ResolvedUnitResult, List<AstNode>> _errors = <ResolvedUnitResult, List<AstNode>>{};

  @override
  void applyTo(ResolvedUnitResult unit) {
    final _StopwatchVisitor visitor = _StopwatchVisitor(unit);
    unit.unit.visitChildren(visitor);
    final List<AstNode> violationsInUnit = visitor.stopwatchAccessNodes;
    if (violationsInUnit.isNotEmpty) {
      _errors.putIfAbsent(unit, () => <AstNode>[]).addAll(violationsInUnit);
    }
  }

  @override
  void reportViolations(String workingDirectory) {
    if (_errors.isEmpty) {
      return;
    }

    String locationInFile(ResolvedUnitResult unit, AstNode node) {
      return '${path.relative(path.relative(unit.path, from: workingDirectory))}:${unit.lineInfo.getLocation(node.offset).lineNumber}';
    }

    foundError(<String>[
      for (final MapEntry<ResolvedUnitResult, List<AstNode>> entry in _errors.entries)
        for (final AstNode node in entry.value)
          '${locationInFile(entry.key, node)}: ${node.parent}',
      '\n${bold}Stopwatches introduce flakes by falling out of sync with the FakeAsync used in testing.$reset',
      'A Stopwatch that stays in sync with FakeAsync is available through the Gesture or Test bindings, through samplingClock.'
    ]);
  }

  @override
  String toString() => 'No "Stopwatch"';
}

// This visitor finds invocation sites of Stopwatch (and subclasses) constructors
// and references to "external" functions that return a Stopwatch (and subclasses),
// including constructors, and put them in the stopwatchAccessNodes list.
class _StopwatchVisitor extends RecursiveAstVisitor<void> {
  _StopwatchVisitor(this.compilationUnit);

  final ResolvedUnitResult compilationUnit;

  final List<AstNode> stopwatchAccessNodes = <AstNode>[];

  final Map<ClassElement, bool> _isStopwatchClassElementCache = <ClassElement, bool>{};

  bool _checkIfImplementsStopwatchRecursively(ClassElement classElement) {
    if (classElement.library.isDartCore) {
      return classElement.name == 'Stopwatch';
    }
    return classElement.allSupertypes.any((InterfaceType interface) {
      final InterfaceElement interfaceElement = interface.element;
      return interfaceElement is ClassElement && _implementsStopwatch(interfaceElement);
    });
  }

  // The cached version, call this method instead of _checkIfImplementsStopwatchRecursively.
  bool _implementsStopwatch(ClassElement classElement) {
    return classElement.library.isDartCore
      ? classElement.name == 'Stopwatch'
      :_isStopwatchClassElementCache.putIfAbsent(classElement, () => _checkIfImplementsStopwatchRecursively(classElement));
  }

  bool _isInternal(LibraryElement libraryElement) {
    return path.isWithin(
      compilationUnit.session.analysisContext.contextRoot.root.path,
      libraryElement.source.fullName,
    );
  }

  bool _hasTrailingFlutterIgnore(AstNode node) {
    return compilationUnit.content
      .substring(node.offset + node.length, compilationUnit.lineInfo.getOffsetOfLineAfter(node.offset + node.length))
      .contains(_ignoreStopwatch);
  }

  // We don't care about directives or comments, skip them.
  @override
  void visitImportDirective(ImportDirective node) { }

  @override
  void visitExportDirective(ExportDirective node) { }

  @override
  void visitComment(Comment node) { }

  @override
  void visitConstructorName(ConstructorName node) {
    final Element? element = node.staticElement;
    if (element is! ConstructorElement) {
      assert(false, '$element of $node is not a ConstructorElement.');
      return;
    }
    final bool isAllowed = switch (element.returnType) {
      InterfaceType(element: final ClassElement classElement) => !_implementsStopwatch(classElement),
      InterfaceType(element: InterfaceElement()) => true,
    };
    if (isAllowed || _hasTrailingFlutterIgnore(node)) {
      return;
    }
    stopwatchAccessNodes.add(node);
  }

  @override
  void visitSimpleIdentifier(SimpleIdentifier node) {
    final bool isAllowed = switch (node.staticElement) {
      ExecutableElement(
        returnType: DartType(element: final ClassElement classElement),
        library: final LibraryElement libraryElement
      ) => _isInternal(libraryElement) || !_implementsStopwatch(classElement),
      Element() || null => true,
    };
    if (isAllowed || _hasTrailingFlutterIgnore(node)) {
      return;
    }
    stopwatchAccessNodes.add(node);
  }
}
