import includes from "lodash/collection/includes";
import * as t from "../../../types";

function getSpreadLiteral(spread, scope) {
  return scope.toArray(spread.argument, true);
}

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

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

  var _props = [];

  var push = function () {
    if (!_props.length) return;
    nodes.push(t.arrayExpression(_props));
    _props = [];
  };

  for (var i = 0; i < props.length; i++) {
    var prop = props[i];
    if (t.isSpreadElement(prop)) {
      push();
      nodes.push(getSpreadLiteral(prop, scope));
    } else {
      _props.push(prop);
    }
  }

  push();

  return nodes;
}

export var check = t.isSpreadElement;

export function ArrayExpression(node, parent, scope) {
  var elements = node.elements;
  if (!hasSpread(elements)) return;

  var nodes = build(elements, scope);
  var first = nodes.shift();

  if (!t.isArrayExpression(first)) {
    nodes.unshift(first);
    first = t.arrayExpression([]);
  }

  return t.callExpression(t.memberExpression(first, t.identifier("concat")), nodes);
}

export function CallExpression(node, parent, scope) {
  var args = node.arguments;
  if (!hasSpread(args)) return;

  var contextLiteral = t.identifier("undefined");

  node.arguments = [];

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

  var first = nodes.shift();
  if (nodes.length) {
    node.arguments.push(t.callExpression(t.memberExpression(first, t.identifier("concat")), nodes));
  } else {
    node.arguments.push(first);
  }

  var callee = node.callee;

  if (this.get("callee").isMemberExpression()) {
    var temp = scope.generateMemoisedReference(callee.object);
    if (temp) {
      callee.object = t.assignmentExpression("=", temp, callee.object);
      contextLiteral = temp;
    } else {
      contextLiteral = callee.object;
    }
    t.appendToMemberExpression(callee, t.identifier("apply"));
  } else {
    node.callee = t.memberExpression(node.callee, t.identifier("apply"));
  }

  node.arguments.unshift(contextLiteral);
}

export function NewExpression(node, parent, scope, file) {
  var args = node.arguments;
  if (!hasSpread(args)) return;

  var nativeType = this.get("callee").isIdentifier() && includes(t.NATIVE_TYPE_NAMES, node.callee.name);

  var nodes = build(args, scope);

  if (nativeType) {
    nodes.unshift(t.arrayExpression([t.literal(null)]));
  }

  var first = nodes.shift();

  if (nodes.length) {
    args = t.callExpression(t.memberExpression(first, t.identifier("concat")), nodes);
  } else {
    args = first;
  }

  if (nativeType) {
    return t.newExpression(
      t.callExpression(
        t.memberExpression(file.addHelper("bind"), t.identifier("apply")),
        [node.callee, args]
      ),
      []
    );
  } else {
    return t.callExpression(file.addHelper("apply-constructor"), [node.callee, args]);
  }
}

@@ -2392,222 +2392,34 @@
 ar n
-ativeType = this.get(%22callee%22).isIdentifier() && includes(t.NATIVE_TYPE_NAMES, node.callee.name);%0A%0A  var nodes = build(args, scope);%0A%0A  if (nativeType) %7B%0A    nodes.unshift(t.arrayExpression(%5Bt.literal(null)%5D));%0A  %7D
+odes = build(args, scope);
 %0A%0A  
@@ -2593,30 +2593,8 @@
  %7D%0A%0A
-  if (nativeType) %7B%0A  
   re
@@ -2619,18 +2619,16 @@
 on(%0A    
-  
 t.callEx
@@ -2643,18 +2643,16 @@
 (%0A      
- 
- 
 t.member
@@ -2716,18 +2716,16 @@
 ,%0A      
-  
 %5Bnode.ca
@@ -2744,15 +2744,11 @@
     
-  
 ),%0A
-  
     
@@ -2756,113 +2756,9 @@
 %5D%0A  
-  );%0A  %7D else %7B%0A    return t.callExpression(file.addHelper(%22apply-constructor%22), %5Bnode.callee, args%5D);%0A  %7D
+);
 %0A%7D%0A

remove apply-constructor helper from es6.spread transformer - fixes #1052