// Copyright (c) 2020, 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 'dart:math' as math;

import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';

import 'package:scrape/scrape.dart';

/// The paths to each build() method and its maximum nesting level.
final buildMethods = <String, int>{};

bool simplifyNames = false;

void main(List<String> arguments) {
  arguments = arguments.toList();
  simplifyNames = arguments.remove('--simplify');
  var allCode = arguments.remove('--all');

  Scrape()
    // The number of levels of nesting active when each argument appears.
    ..addHistogram('Nesting depth')
    // The number of levels of nesting active when each argument appears without
    // counting lists.
    ..addHistogram('Ignoring lists')
    // The number of levels of "child" or "children" named parameter nesting
    // when each argument appears.
    ..addHistogram('Child nesting depth')
    ..addHistogram('Argument names')
    // Strings that describe the structure of each nested argument.
    ..addHistogram('Argument nesting')
    ..addVisitor(() => NestingVisitor(allCode: allCode))
    ..runCommandLine(arguments);

  var methods = buildMethods.keys.toList();
  methods.sort((a, b) => buildMethods[b]!.compareTo(buildMethods[a]!));
  for (var method in methods) {
    print('${buildMethods[method].toString().padLeft(3)}: $method');
  }
  print('${buildMethods.length} build() methods');
}

class NestingVisitor extends ScrapeVisitor {
  final List<String> _stack = [];

  final bool _allCode;
  bool _pushed = false;
  int _deepestNesting = 0;

  NestingVisitor({bool? allCode}) : _allCode = allCode ?? false;

  @override
  void beforeVisitBuildMethod(Declaration node) {
    _deepestNesting = 0;
  }

  @override
  void afterVisitBuildMethod(Declaration node) {
    var startLine = lineInfo.getLocation(node.offset).lineNumber;
    buildMethods['$path:$startLine'] = _deepestNesting;
  }

  @override
  void visitArgumentList(ArgumentList node) {
    // Only argument lists with trailing commas get indentation.
    if (node.arguments.isNotEmpty &&
        node.arguments.last.endToken.next!.type == TokenType.COMMA) {
      String name;
      var parent = node.parent;
      if (parent is MethodInvocation) {
        name = parent.methodName.name;
      } else if (parent is InstanceCreationExpression) {
        name = parent.constructorName.toString();
      } else if (parent is SuperConstructorInvocation) {
        name = 'super.${parent.constructorName}';
      } else {
        name = '?(${parent.runtimeType})?';
      }

      if (simplifyNames) {
        name = '';
      }

      for (var argument in node.arguments) {
        var argName =
            argument is NamedExpression ? argument.name.label.name : '';

        if (_allCode || isInFlutterBuildMethod) {
          record('Argument names', argName);
        }

        if (simplifyNames && argName != 'child' && argName != 'children') {
          argName = '_';
        }

        _push('$name($argName:');
        argument.accept(this);
        _pop();
      }
    } else {
      node.visitChildren(this);
    }
  }

  @override
  void visitBlock(Block node) {
    var isFunction = node.parent is BlockFunctionBody;
    if (!isFunction) _push('{');
    node.visitChildren(this);
    if (!isFunction) _pop();
  }

  @override
  void visitExpressionFunctionBody(ExpressionFunctionBody node) {
    _push('=>');
    node.visitChildren(this);
    _pop();
  }

  @override
  void visitFunctionExpression(FunctionExpression node) {
    var isDeclaration = node.parent is FunctionDeclaration;
    if (!isDeclaration) _push('(){');
    node.visitChildren(this);
    if (!isDeclaration) _pop();
  }

  @override
  void visitListLiteral(ListLiteral node) {
    for (var element in node.elements) {
      _push('[');
      element.accept(this);
      _pop();
    }
  }

  @override
  void visitSetOrMapLiteral(SetOrMapLiteral node) {
    for (var element in node.elements) {
      _push('{');
      element.accept(this);
      _pop();
    }
  }

  void _push(String string) {
    _stack.add(string);
    _pushed = true;
    _deepestNesting = math.max(_deepestNesting, _stack.length);
  }

  void _pop() {
    if (_pushed && (_allCode || isInFlutterBuildMethod)) {
      record('Argument nesting', _stack.join(' '));
      record('Nesting depth', _stack.length);
      record('Ignoring lists', _stack.where((s) => s != '[').length);
      record('Child nesting depth',
          _stack.where((s) => s.contains('child')).length);
    }
    _pushed = false;
    _stack.removeLast();
  }
}
