"use strict";

exports.__esModule = true;
exports.default = _default;

var _core = require("@babel/core");

function _default(api, options) {
  var loose = options.loose;

  function getSpreadLiteral(spread, scope) {
    if (loose && !_core.types.isIdentifier(spread.argument, {
      name: "arguments"
    })) {
      return spread.argument;
    } else {
      return scope.toArray(spread.argument, true);
    }
  }

  function hasSpread(nodes) {
    for (var i = 0; i < nodes.length; i++) {
      if (_core.types.isSpreadElement(nodes[i])) {
        return true;
      }
    }

    return false;
  }

  function push(_props, nodes) {
    if (!_props.length) return _props;
    nodes.push(_core.types.arrayExpression(_props));
    return [];
  }

  function build(props, scope) {
    var nodes = [];
    var _props = [];

    for (var _iterator = props, _isArray = Array.isArray(_iterator), _i = 0, _iterator = _isArray ? _iterator : _iterator[Symbol.iterator]();;) {
      var _ref;

      if (_isArray) {
        if (_i >= _iterator.length) break;
        _ref = _iterator[_i++];
      } else {
        _i = _iterator.next();
        if (_i.done) break;
        _ref = _i.value;
      }

      var _prop = _ref;

      if (_core.types.isSpreadElement(_prop)) {
        _props = push(_props, nodes);
        nodes.push(getSpreadLiteral(_prop, scope));
      } else {
        _props.push(_prop);
      }
    }

    push(_props, nodes);
    return nodes;
  }

  return {
    visitor: {
      ArrayExpression: function ArrayExpression(path, state) {
        var node = path.node,
            scope = path.scope;
        var elements = node.elements;
        if (!hasSpread(elements)) return;
        var nodes = build(elements, scope, state);
        var first = nodes.shift();

        if (nodes.length === 0 && first !== elements[0].argument) {
          path.replaceWith(first);
          return;
        }

        path.replaceWith(_core.types.callExpression(_core.types.memberExpression(first, _core.types.identifier("concat")), nodes));
      },
      CallExpression: function CallExpression(path, state) {
        var node = path.node,
            scope = path.scope;
        var args = node.arguments;
        if (!hasSpread(args)) return;
        var calleePath = path.get("callee");
        if (calleePath.isSuper()) return;
        var contextLiteral = scope.buildUndefinedNode();
        node.arguments = [];
        var nodes;

        if (args.length === 1 && args[0].argument.name === "arguments") {
          nodes = [args[0].argument];
        } else {
          nodes = build(args, scope, state);
        }

        var first = nodes.shift();

        if (nodes.length) {
          node.arguments.push(_core.types.callExpression(_core.types.memberExpression(first, _core.types.identifier("concat")), nodes));
        } else {
          node.arguments.push(first);
        }

        var callee = node.callee;

        if (calleePath.isMemberExpression()) {
          var temp = scope.maybeGenerateMemoised(callee.object);

          if (temp) {
            callee.object = _core.types.assignmentExpression("=", temp, callee.object);
            contextLiteral = temp;
          } else {
            contextLiteral = _core.types.cloneNode(callee.object);
          }

          _core.types.appendToMemberExpression(callee, _core.types.identifier("apply"));
        } else {
          node.callee = _core.types.memberExpression(node.callee, _core.types.identifier("apply"));
        }

        if (_core.types.isSuper(contextLiteral)) {
          contextLiteral = _core.types.thisExpression();
        }

        node.arguments.unshift(_core.types.cloneNode(contextLiteral));
      },
      NewExpression: function NewExpression(path, state) {
        var node = path.node,
            scope = path.scope;
        var args = node.arguments;
        if (!hasSpread(args)) return;
        var nodes = build(args, scope, state);

        var context = _core.types.arrayExpression([_core.types.nullLiteral()]);

        args = _core.types.callExpression(_core.types.memberExpression(context, _core.types.identifier("concat")), nodes);
        path.replaceWith(_core.types.newExpression(_core.types.callExpression(_core.types.memberExpression(_core.types.memberExpression(_core.types.memberExpression(_core.types.identifier("Function"), _core.types.identifier("prototype")), _core.types.identifier("bind")), _core.types.identifier("apply")), [node.callee, args]), []));
      }
    }
  };
}