import forEach from 'lodash.foreach';
import merge from 'lodash.merge';
import union from 'lodash.union';
import warning from 'warning';

import actionTypes from '../actions/types';
import connectors from './connectors';
import processNode from './process-node';
import store from './store';

// Default state
// state will be composed of connectors data, e.g.
// {
//   connector_1: {
//     pages: [{...}, {...}]
//   },
//   connector_2: {
//     page: {...}
//   }
// }
const defaultState = {};

export default function graphqlReducer (state = defaultState, action = {}) {
  if ((action.type === actionTypes.query || action.type === actionTypes.mutation) && action.data && action.fragments) {
    const isMutation = action.type === actionTypes.mutation;
    const isRemoveMutation = isMutation && action.mutationType === 'REMOVE';
    let connectorsToUpdate = action.connectors && Object.keys(action.connectors) || [];
    let nodes = [];

    if (isRemoveMutation) {
      forEach(action.fragments, (fragment, queryName) => {
        if (fragment._id) {
          const queryData = action.data[queryName];
          if (queryData && queryData._id) {
            // Remove from store
            store.removeNode(queryData._id);

            // Remove from connectors
            connectorsToUpdate = connectors.removeNode(queryData._id);
          } else {
            warning(false, 'RELATE: Remove action failed');
            // TODO handle error in some way?
          }
        }
      });
    } else {
      forEach(action.fragments, (fragment, queryName) => {
        const nodesProcessed = processNode(action.data[queryName], fragment, queryName); // { relativeNodes: [], nodes: [], changes: {} }

        // DB changes
        store.updateNodes(nodesProcessed.changes);

        // Save nodes changed to later check which connectors to update
        nodes = union(nodes, nodesProcessed.nodes);

        // Connectors
        if (action.connectors) {
          connectors.processConnectors(action.connectors, queryName, nodesProcessed.relativeNodes, nodesProcessed.nodes);
        }

        // Mutations
        if (isMutation) {
          connectorsToUpdate = connectors.checkMutationListeners(queryName, nodesProcessed.relativeNodes, nodesProcessed.nodes);
        }
      });
    }

    // Check more connectors than need to update
    connectorsToUpdate = connectorsToUpdate.concat(connectors.getConnectorsToUpdate(nodes, connectorsToUpdate));

    // Calculate connectors data
    const changes = {};
    forEach(connectorsToUpdate, (connectorId) => {
      changes[connectorId] = connectors.generateConnectorData(connectorId);
    });

    return merge({}, state, changes);
  }

  if (action.type === actionTypes.removeConnector) {
    const newState = Object.assign({}, state);
    delete newState[action.id];
    connectors.deleteConnector(action.id);
    // TODO Delete no longer needed data from state? or maintain for future cache?
    return newState;
  }

  return state;
}

@@ -1331,24 +1331,198 @@
 ryData._id);
+%0A%0A            // Check connectors listening to this mutation%0A            connectorsToUpdate = union(connectorsToUpdate, connectors.checkMutationListeners(queryName, %5B%5D, %5B%5D));
 %0A          %7D
@@ -2334,32 +2334,58 @@
 ectorsToUpdate =
+ union(connectorsToUpdate,
  connectors.chec
@@ -2457,32 +2457,33 @@
 Processed.nodes)
+)
 ;%0A        %7D%0A    

check for connectors listening a remove mutation